Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add example taskobj.c to doc/6.externs to demonstrate the task API
- Loading branch information
1 parent
4a27dc0
commit b396e58
Showing
5 changed files
with
229 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
/* This object shows how to run asynchronous tasks with the task API. | ||
* The "read" method reads the content of the given file in the background. | ||
* It outputs the file size on success and -1 on failure. | ||
* With the "get" method you can read a single byte. */ | ||
|
||
#include "m_pd.h" | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
|
||
#ifdef _WIN32 | ||
#include <windows.h> | ||
#else | ||
#include <unistd.h> | ||
#endif | ||
|
||
static t_class *taskobj_class; | ||
|
||
typedef struct _taskobj | ||
{ | ||
t_object x_obj; | ||
t_outlet *x_statusout; | ||
t_outlet *x_byteout; | ||
char *x_data; | ||
int x_size; | ||
t_task *x_current; | ||
} t_taskobj; | ||
|
||
typedef struct _taskdata | ||
{ | ||
char filename[256]; | ||
char *data; | ||
int size; | ||
int err; | ||
float ms; | ||
} t_taskdata; | ||
|
||
static void taskobj_worker(t_taskdata *x) | ||
{ | ||
/* free old file data */ | ||
if (x->data) | ||
free(x->data); | ||
x->data = 0; | ||
x->size = 0; | ||
/* try to read new file data */ | ||
FILE *fp = fopen(x->filename, "rb"); | ||
if (fp) | ||
{ | ||
char *data; | ||
size_t size; | ||
// get file size | ||
fseek(fp, 0, SEEK_END); | ||
size = ftell(fp); | ||
fseek(fp, 0, SEEK_SET); | ||
// allocate buffer | ||
data = malloc(size); | ||
if (data) | ||
{ | ||
/* read file into buffer */ | ||
size_t result = fread(data, 1, size, fp); | ||
if (result == size) /* success */ | ||
{ | ||
x->data = data; | ||
x->size = size; | ||
if (x->ms > 0) | ||
{ | ||
/* sleep to simulate work */ | ||
#ifdef _WIN32 | ||
Sleep(x->ms); | ||
#else | ||
usleep(x->ms * 1000.0); | ||
#endif | ||
} | ||
} | ||
else /* fail */ | ||
{ | ||
x->err = errno; | ||
free(data); | ||
} | ||
} | ||
} | ||
else /* catch error */ | ||
x->err = errno; | ||
} | ||
|
||
static void taskobj_callback(t_taskobj *x, t_taskdata *y) | ||
{ | ||
if (x) /* task has been completed */ | ||
{ | ||
/* move file data to object */ | ||
x->x_data = y->data; | ||
x->x_size = y->size; | ||
/* task has completed and is now invalid. | ||
do this BEFORE sending the message! */ | ||
x->x_current = 0; | ||
/* notify */ | ||
if (x->x_data) /* success */ | ||
outlet_float(x->x_statusout, x->x_size); | ||
else /* fail */ | ||
{ | ||
pd_error(x, "could not read file '%s': %s (%d)", | ||
y->filename, strerror(y->err), y->err); | ||
outlet_float(x->x_statusout, -1); | ||
} | ||
} | ||
else /* task has been cancelled */ | ||
{ | ||
/* free the previous file data to avoid a memory leak! */ | ||
if (y->data) | ||
free(y->data); | ||
} | ||
/* free the task data */ | ||
freebytes(y, sizeof(t_taskdata)); | ||
} | ||
|
||
static void taskobj_read(t_taskobj *x, t_symbol *filename, t_floatarg ms) | ||
{ | ||
t_taskdata *y = (t_taskdata *)getbytes(sizeof(t_taskdata)); | ||
y->err = 0; | ||
y->ms = ms; | ||
/* move old file data */ | ||
y->data = x->x_data; | ||
y->size = x->x_size; | ||
x->x_data = 0; | ||
x->x_size = 0; | ||
/* store file name */ | ||
snprintf(y->filename, sizeof(y->filename), "%s", filename->s_name); | ||
/* cancel running task, so that we don't accidentally output | ||
a message while we are still reading THIS file */ | ||
if (x->x_current) | ||
task_cancel(x->x_current, 0); | ||
/* schedule task */ | ||
x->x_current = task_sched((t_pd *)x, y, | ||
(t_task_workfn)taskobj_worker, (t_task_callback)taskobj_callback); | ||
} | ||
|
||
static void taskobj_get(t_taskobj *x, t_floatarg f) | ||
{ | ||
if (x->x_data) | ||
{ | ||
int i = f; | ||
if (i >= 0 && i < x->x_size) | ||
outlet_float(x->x_byteout, x->x_data[i]); | ||
else | ||
pd_error(x, "index %d out of range!", i); | ||
} | ||
else | ||
pd_error(x, "no file loaded!"); | ||
} | ||
|
||
static void *taskobj_new(void) | ||
{ | ||
t_taskobj *x = (t_taskobj *)pd_new(taskobj_class); | ||
x->x_data = 0; | ||
x->x_size = 0; | ||
x->x_current = 0; | ||
x->x_statusout = outlet_new(&x->x_obj, 0); | ||
x->x_byteout = outlet_new(&x->x_obj, 0); | ||
return x; | ||
} | ||
|
||
static void taskobj_free(t_taskobj *x) | ||
{ | ||
/* cancel pending tasks */ | ||
task_join((t_pd *)x); | ||
/* free file data */ | ||
if (x->x_data) | ||
free(x->x_data); | ||
} | ||
|
||
void taskobj_setup(void) | ||
{ | ||
taskobj_class = class_new(gensym("taskobj"), | ||
(t_newmethod)taskobj_new, (t_method)taskobj_free, | ||
sizeof(t_taskobj), 0, 0); | ||
class_addmethod(taskobj_class, (t_method)taskobj_read, | ||
gensym("read"), A_SYMBOL, A_DEFFLOAT, 0); | ||
class_addmethod(taskobj_class, (t_method)taskobj_get, | ||
gensym("get"), A_FLOAT, 0); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#N canvas 523 166 455 399 12; | ||
#X obj 33 77 openpanel; | ||
#X obj 33 55 bng 15 250 50 0 empty empty empty 17 7 0 10 #fcfcfc #000000 | ||
#000000; | ||
#X floatatom 33 340 8 0 0 0 - - -; | ||
#X floatatom 79 315 5 0 0 0 - - -; | ||
#X text 122 314 byte; | ||
#X msg 124 253 get \$1; | ||
#X floatatom 124 227 8 0 0 0 - - -; | ||
#X text 31 27 try to open a huge file while running the test tone; | ||
#X obj 48 133 realtime; | ||
#X floatatom 48 157 8 0 0 0 - - -; | ||
#X obj 33 313 t f b; | ||
#X obj 33 101 t s b; | ||
#X text 180 254 get a single byte; | ||
#X text 98 341 file size (or -1 on failure); | ||
#X obj 33 289 taskobj; | ||
#X obj 33 188 pack s f; | ||
#X msg 33 227 read \$1 \$2; | ||
#X floatatom 103 189 6 0 0 0 - - -; | ||
#X text 152 189 sleep (ms); | ||
#X connect 0 0 11 0; | ||
#X connect 1 0 0 0; | ||
#X connect 5 0 14 0; | ||
#X connect 6 0 5 0; | ||
#X connect 8 0 9 0; | ||
#X connect 10 0 2 0; | ||
#X connect 10 1 8 1; | ||
#X connect 11 0 15 0; | ||
#X connect 11 1 8 0; | ||
#X connect 14 0 10 0; | ||
#X connect 14 1 3 0; | ||
#X connect 15 0 16 0; | ||
#X connect 16 0 14 0; | ||
#X connect 17 0 15 1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters