aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Peach <mrpeach@users.sourceforge.net>2007-09-24 21:01:24 +0000
committerMartin Peach <mrpeach@users.sourceforge.net>2007-09-24 21:01:24 +0000
commitd62b337b9bc1d10917e5cf2ec9193fa1d4c4a5ec (patch)
tree2fe0f91f5b767c59daf0c60ffb7d002ec7838830
parentd7999dd4c3992348c16aeb14bbe4de5a0ed80e2c (diff)
An object to manipulate binary files in pd.
svn path=/trunk/externals/mrpeach/; revision=8756
-rwxr-xr-xbinfile/binfile-help.pd81
-rwxr-xr-xbinfile/binfile.c303
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 */