diff options
author | Martin Peach <mrpeach@users.sourceforge.net> | 2007-09-24 21:01:24 +0000 |
---|---|---|
committer | Martin Peach <mrpeach@users.sourceforge.net> | 2007-09-24 21:01:24 +0000 |
commit | d62b337b9bc1d10917e5cf2ec9193fa1d4c4a5ec (patch) | |
tree | 2fe0f91f5b767c59daf0c60ffb7d002ec7838830 /binfile | |
parent | d7999dd4c3992348c16aeb14bbe4de5a0ed80e2c (diff) |
An object to manipulate binary files in pd.
svn path=/trunk/externals/mrpeach/; revision=8756
Diffstat (limited to 'binfile')
-rwxr-xr-x | binfile/binfile-help.pd | 81 | ||||
-rwxr-xr-x | binfile/binfile.c | 303 |
2 files changed, 384 insertions, 0 deletions
diff --git a/binfile/binfile-help.pd b/binfile/binfile-help.pd new file mode 100755 index 0000000..5bf63e2 --- /dev/null +++ b/binfile/binfile-help.pd @@ -0,0 +1,81 @@ +#N canvas 364 300 1105 584 12;
+#X msg 546 150 rewind;
+#X obj 85 549 textfile;
+#X msg 536 120 bang;
+#X msg 545 204 clear;
+#X msg 545 305 set 2 4 6 8;
+#X obj 25 15 binfile;
+#X text 88 14 read and write binary files;
+#X text 25 144 You can also use this object simply for storing heterogeneous
+sequences of bytes.;
+#X msg 545 231 add 10 20 255;
+#X msg 545 177 read afile.bin;
+#X obj 480 408 binfile;
+#X text 814 548 Martin Peach 2007/09/24;
+#X text 149 548 to read and write text files;
+#X msg 545 331 write afile.bin;
+#X text 612 426 This outlet gives a bang when you hit the end of the
+sequence.;
+#X text 478 502 This outlet gives the bytes in sequence \, or bangs
+if no more bytes.;
+#X text 645 230 add a list of byte-floats to the buffer;
+#X text 630 304 clear the buffer and then add some bytes;
+#X text 590 203 empty the buffer;
+#X text 597 149 set the read pointer to the beginnning of the buffer
+;
+#X text 575 119 output one byte from the buffer as a float;
+#X text 661 330 write the entire buffer to a file;
+#X text 653 176 read a file into the buffer \, replacing any previous
+contents;
+#X obj 480 481 print one;
+#X obj 526 437 bng 15 250 50 0 empty empty empty 17 7 0 10 -258113
+-257985 -1;
+#X obj 495 123 bng 15 250 50 0 empty empty empty 17 7 0 10 -4034 -257985
+-1;
+#X text 16 548 See also:;
+#X obj 480 53 openpanel;
+#X obj 480 32 bng 15 250 50 0 empty empty read_any_file_into_buffer
+17 7 0 10 -4032 -258113 -1;
+#X msg 480 79 read \$1;
+#X obj 324 216 bng 15 250 50 0 empty empty save_buffer_as_any_file
+17 7 0 10 -4032 -258113 -1;
+#X msg 324 264 write \$1;
+#X obj 324 238 savepanel;
+#X text 514 120 or;
+#X msg 545 257 77 128 129 130;
+#X text 25 38 The binfile object reads and writes binary files to and
+from a buffer in memory. You can read a file and output its contents
+one byte at a time as floats.;
+#X text 25 91 To add bytes to the buffer \, first send "clear" to empty
+the buffer and then "add" to add bytes. Finally \, "write" will save
+the entire buffer as a binary file.;
+#X floatatom 545 282 5 0 0 0 - - -;
+#X text 586 281 add one byte \, same as "add";
+#X text 654 256 add a list of bytes \, same as "add";
+#X msg 545 357 info;
+#X obj 503 455 print info;
+#X obj 543 432 print end;
+#X text 583 454 This outlet gives a list of info from the info message.
+;
+#X text 583 356 output current buffer length and pointer values.;
+#X connect 0 0 10 0;
+#X connect 2 0 10 0;
+#X connect 3 0 10 0;
+#X connect 4 0 10 0;
+#X connect 8 0 10 0;
+#X connect 9 0 10 0;
+#X connect 10 0 23 0;
+#X connect 10 1 41 0;
+#X connect 10 2 24 0;
+#X connect 10 2 42 0;
+#X connect 13 0 10 0;
+#X connect 25 0 10 0;
+#X connect 27 0 29 0;
+#X connect 28 0 27 0;
+#X connect 29 0 10 0;
+#X connect 30 0 32 0;
+#X connect 31 0 10 0;
+#X connect 32 0 31 0;
+#X connect 34 0 10 0;
+#X connect 37 0 10 0;
+#X connect 40 0 10 0;
diff --git a/binfile/binfile.c b/binfile/binfile.c new file mode 100755 index 0000000..be65a70 --- /dev/null +++ b/binfile/binfile.c @@ -0,0 +1,303 @@ +/* binfile.c An external for Pure Data that reads and writes binary files +* Copyright (C) 2007 Martin Peach +* +* 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 +* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +* +* The latest version of this file can be found at: +* http://pure-data.cvs.sourceforge.net/pure-data/externals/mrpeach/binfile/ +* +* martin.peach@sympatico.ca +*/ + +#include "m_pd.h" +#include <stdio.h> +#include <string.h> + +static t_class *binfile_class; + +#define ALLOC_BLOCK_SIZE 65536 /* number of bytes to add when resizing buffer */ + +typedef struct t_binfile +{ + t_object x_obj; + t_outlet *x_bin_outlet; + t_outlet *x_info_outlet; + t_outlet *x_bang_outlet; + FILE *x_fP; + char x_fPath[MAXPDSTRING]; + char *x_buf; /* read/write buffer in memory for file contents */ + size_t x_buf_length; /* current length of buf */ + size_t x_rd_offset; /* current read offset into the buffer */ + size_t x_wr_offset; /* current write offset into the buffer */ +} t_binfile; + +static void binfile_rewind (t_binfile *x); +static void binfile_free(t_binfile *x); +static FILE *binfile_open_path(t_binfile *x, char *path, char *mode); +static void binfile_read(t_binfile *x, t_symbol *path); +static void binfile_write(t_binfile *x, t_symbol *path); +static void binfile_bang(t_binfile *x); +static void binfile_float(t_binfile *x, t_float val); +static void binfile_list(t_binfile *x, t_symbol *s, int argc, t_atom *argv); +static void binfile_add(t_binfile *x, t_symbol *s, int argc, t_atom *argv); +static void binfile_clear(t_binfile *x); +static void binfile_info(t_binfile *x); +static void binfile_set(t_binfile *x, t_symbol *s, int argc, t_atom *argv); +static void *binfile_new(t_symbol *s, int argc, t_atom *argv); +void binfile_setup(void); + +void binfile_setup(void) +{ + binfile_class = class_new (gensym("binfile"), + (t_newmethod) binfile_new, + (t_method)binfile_free, sizeof(t_binfile), + CLASS_DEFAULT, + A_GIMME, 0); + + class_addbang(binfile_class, binfile_bang); + class_addfloat(binfile_class, binfile_float); + class_addlist(binfile_class, binfile_list); + class_addmethod(binfile_class, (t_method)binfile_read, gensym("read"), A_DEFSYMBOL, 0); + class_addmethod(binfile_class, (t_method)binfile_write, gensym("write"), A_DEFSYMBOL, 0); + class_addmethod(binfile_class, (t_method)binfile_add, gensym("add"), A_GIMME, 0); + class_addmethod(binfile_class, (t_method)binfile_set, gensym("set"), A_GIMME, 0); + class_addmethod(binfile_class, (t_method)binfile_clear, gensym("clear"), 0); + class_addmethod(binfile_class, (t_method)binfile_rewind, gensym("rewind"), 0); + class_addmethod(binfile_class, (t_method)binfile_info, gensym("info"), 0); +} + +static void *binfile_new(t_symbol *s, int argc, t_atom *argv) +{ + t_binfile *x = (t_binfile *)pd_new(binfile_class); + t_symbol *pathSymbol; + int i; + + if (x == NULL) + { + error("binfile: Could not create..."); + return x; + } + x->x_fP = NULL; + x->x_fPath[0] = '\0'; + x->x_buf_length = ALLOC_BLOCK_SIZE; + /* find the first string in the arg list and interpret it as a path to a file */ + for (i = 0; i < argc; ++i) + { + if (argv[i].a_type == A_SYMBOL) + { + pathSymbol = atom_getsymbol(&argv[i]); + if (pathSymbol != NULL) + binfile_read(x, pathSymbol); + } + } + /* find the first float in the arg list and interpret it as the size of the buffer */ + for (i = 0; i < argc; ++i) + { + if (argv[i].a_type == A_FLOAT) + { + x->x_buf_length = atom_getfloat(&argv[i]); + break; + } + } + if ((x->x_buf = getbytes(x->x_buf_length)) == NULL) + error ("binfile: Unable to allocate %lu bytes for buffer", x->x_buf_length); + x->x_bin_outlet = outlet_new(&x->x_obj, gensym("float")); + x->x_info_outlet = outlet_new(&x->x_obj, gensym("list")); + x->x_bang_outlet = outlet_new(&x->x_obj, gensym("bang")); /* bang at end of file */ + return (void *)x; +} + +static void binfile_free(t_binfile *x) +{ + if (x->x_buf != NULL) + freebytes(x->x_buf, x->x_buf_length); + x->x_buf = NULL; + x->x_buf_length = 0L; +} + +static FILE *binfile_open_path(t_binfile *x, char *path, char *mode) +/* path is a string. Up to PATH_BUF_SIZE-1 characters will be copied into x->x_fPath. */ +/* mode should be "rb" or "wb" */ +/* x->x_fPath will be used as a file name to open. */ +/* binfile_open_path attempts to open the file for binary mode reading. */ +/* Returns FILE pointer if successful, else 0. */ +{ + FILE *fP; + char tryPath[MAXPDSTRING]; + + strncpy(tryPath, path, MAXPDSTRING-1); /* copy path into a length-limited buffer */ + /* ...if it doesn't work we won't mess up x->x_fPath */ + tryPath[MAXPDSTRING-1] = '\0'; /* just make sure there is a null termination */ + + return fopen(tryPath, mode); +} + +static void binfile_write(t_binfile *x, t_symbol *path) +/* open the file for writing and write the entire buffer to it, then close it */ +{ + size_t bytes_written = 0L; + + if (0==(x->x_fP = binfile_open_path(x, path->s_name, "wb"))) + error("binfile: Unable to open %s for writing", path->s_name); + bytes_written = fwrite(x->x_buf, 1L, x->x_wr_offset, x->x_fP); + if (bytes_written != x->x_wr_offset) post("binfile: %ld bytes written != %ld", bytes_written, x->x_wr_offset); + else post("binfile: wrote %ld bytes to %s", bytes_written, path->s_name); + fclose(x->x_fP); + x->x_fP = NULL; +} + +static void binfile_read(t_binfile *x, t_symbol *path) +/* open the file for reading and load it into the buffer, then close it */ +{ + size_t file_length = 0L; + size_t bytes_read = 0L; + + if (0==(x->x_fP = binfile_open_path(x, path->s_name, "rb"))) + { + error("binfile: Unable to open %s for reading", path->s_name); + return; + } + /* get length of file */ + while (EOF != getc(x->x_fP)) ++file_length; + + if (file_length == 0L) return; + /* get storage for file contents */ + if (0 != x->x_buf) freebytes(x->x_buf, x->x_buf_length); + x->x_buf = getbytes(file_length); + if (NULL == x->x_buf) + { + x->x_buf_length = 0L; + error ("binfile: unable to allocate %ld bytes for %s", file_length, path->s_name); + return; + } + x->x_rd_offset = 0L; + /* read file into buf */ + rewind(x->x_fP); + bytes_read = fread(x->x_buf, 1L, file_length, x->x_fP); + x->x_buf_length = bytes_read; + x->x_wr_offset = x->x_buf_length; + x->x_rd_offset = 0L; + fclose (x->x_fP); + x->x_fP = NULL; + if (bytes_read != file_length) post("binfile length %ld not equal to bytes read (%ld)", file_length, bytes_read); + else post("binfle: read %ld bytes from %s", bytes_read, path->s_name); +} + +static void binfile_bang(t_binfile *x) +/* get the next byte in the file and send it out x_bin_list_outlet */ +{ + unsigned char c; + + if (x->x_rd_offset < x->x_wr_offset) + { + c = x->x_buf[x->x_rd_offset++]; + if (x->x_rd_offset == x->x_wr_offset) outlet_bang(x->x_bang_outlet); + outlet_float(x->x_bin_outlet, (float)c); + } + else outlet_bang(x->x_bin_outlet); +} + +/* The arguments of the ``list''-method +* a pointer to the class-dataspace +* a pointer to the selector-symbol (always &s_list) +* the number of atoms and a pointer to the list of atoms: +*/ + +static void binfile_add(t_binfile *x, t_symbol *s, int argc, t_atom *argv) +/* add a list of bytes to the buffer */ +{ + int i, j; + float f; + + for (i = 0; i < argc; ++i) + { + if (A_FLOAT == argv[i].a_type) + { + j = atom_getint(&argv[i]); + f = atom_getfloat(&argv[i]); + if (j < -128 || j > 255) + { + error("binfile: input (%d) out of range [0..255]", j); + return; + } + if (j != f) + { + error("binfile: input (%f) not an integer", f); + return; + } + if (x->x_buf_length <= x->x_wr_offset) + { + x->x_buf = resizebytes(x->x_buf, x->x_buf_length, x->x_buf_length+ALLOC_BLOCK_SIZE); + if (x->x_buf == NULL) + { + error("binfile: unable to resize buffer"); + return; + } + x->x_buf_length += ALLOC_BLOCK_SIZE; + } + x->x_buf[x->x_wr_offset++] = j; + } + else + { + error("binfile: input %d not a float", i); + return; + } + } +} + +static void binfile_list(t_binfile *x, t_symbol *s, int argc, t_atom *argv) +{ + binfile_add(x, s, argc, argv); +} + +static void binfile_set(t_binfile *x, t_symbol *s, int argc, t_atom *argv) +/* clear then add a list of bytes to the buffer */ +{ + binfile_clear(x); + binfile_add(x, s, argc, argv); +} + +static void binfile_clear(t_binfile *x) +{ + x->x_wr_offset = 0L; + x->x_rd_offset = 0L; +} + +static void binfile_float(t_binfile *x, t_float val) +/* add a single byte to the file */ +{ + t_atom a; + + SETFLOAT(&a, val); + binfile_add(x, gensym("float"), 1, &a); +} + +static void binfile_rewind (t_binfile *x) +{ + x->x_rd_offset = 0L; +} + +static void binfile_info(t_binfile *x) +{ + t_atom *output_atom = getbytes(sizeof(t_atom)); + SETFLOAT(output_atom, x->x_buf_length); + outlet_anything( x->x_info_outlet, gensym("buflength"), 1, output_atom); + SETFLOAT(output_atom, x->x_rd_offset); + outlet_anything( x->x_info_outlet, gensym("readoffset"), 1, output_atom); + SETFLOAT(output_atom, x->x_wr_offset); + outlet_anything( x->x_info_outlet, gensym("writeoffset"), 1, output_atom); + freebytes(output_atom,sizeof(t_atom)); +} +/* fin binfile.c */ |