/* For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. iemlib1 written by Thomas Musil, Copyright (c) IEM KUG Graz Austria 2000 - 2010 */ #include "m_pd.h" #include "iemlib.h" #include #include #include #include #define SFI_HEADER_SAMPLERATE 0 #define SFI_HEADER_FILENAME 1 #define SFI_HEADER_MULTICHANNEL_FILE_LENGTH 2 #define SFI_HEADER_HEADERBYTES 3 #define SFI_HEADER_CHANNELS 4 #define SFI_HEADER_BYTES_PER_SAMPLE 5 #define SFI_HEADER_ENDINESS 6 #define SFI_HEADER_FORMAT_CODE 7 #define SFI_HEADER_SIZE 8 #define SFI_HEADER_CHUNK_SIZE_ESTIMATION 10000 /* --------------------------- soundfile_info -------------------------------- */ /* -- reads only header of a wave-file and outputs the important parameters -- */ static t_class *soundfile_info_class; typedef struct _soundfile_info { t_object x_obj; long *x_begmem; int x_mem_size; t_atom x_at_header[SFI_HEADER_SIZE]; t_canvas *x_canvas; void *x_list_out; } t_soundfile_info; static short soundfile_info_string_to_int16(char *cvec) { short ss=0; unsigned char *uc=(unsigned char *)cvec; ss += (short)(*uc); ss += (short)(*(uc+1)*256); return(ss); } static unsigned long soundfile_info_string_to_uint32(char *cvec) { unsigned long ul=0; unsigned char *uc=(unsigned char *)cvec; ul += (unsigned long)(*uc); ul += (unsigned long)(*(uc+1)*256); ul += (unsigned long)(*(uc+2)*65536); ul += (unsigned long)(*(uc+3)*16777216); return(ul); } static void soundfile_info_uint32_to_string(char *cvec, unsigned long ul) { unsigned char *uc=(unsigned char *)cvec; *uc = (unsigned char)(0x000000ff & ul); *(uc+1) = (unsigned char)(0x000000ff & (ul/256)); *(uc+2) = (unsigned char)(0x000000ff & (ul/65536)); *(uc+3) = (unsigned char)(0x000000ff & (ul/16777216)); return; } static void soundfile_info_overwrite_sr(t_soundfile_info *x, t_symbol *filename, t_floatarg new_sr) { char completefilename[400]; int i, n, n2, n4, filesize, read_chars, header_size=0, ch, bytesperframe, sr, n_frames; FILE *fh; t_atom *at; char *cvec; unsigned long ul_chunk_size, ul_sr; short ss_format, ss_ch, ss_bytesperframe; if(filename->s_name[0] == '/')/*make complete path + filename*/ { strcpy(completefilename, filename->s_name); } else if(((filename->s_name[0] >= 'A')&&(filename->s_name[0] <= 'Z')|| (filename->s_name[0] >= 'a')&&(filename->s_name[0] <= 'z'))&& (filename->s_name[1] == ':')&&(filename->s_name[2] == '/')) { strcpy(completefilename, filename->s_name); } else { strcpy(completefilename, canvas_getdir(x->x_canvas)->s_name); strcat(completefilename, "/"); strcat(completefilename, filename->s_name); } fh = fopen(completefilename,"r+b"); if(!fh) { post("soundfile_info_read: cannot open %s !!\n", completefilename); } else { n = x->x_mem_size; // 10000 bytes n2 = sizeof(short) * x->x_mem_size; n4 = sizeof(long) * x->x_mem_size; fseek(fh, 0, SEEK_END); filesize = ftell(fh); fseek(fh,0,SEEK_SET); read_chars = (int)fread(x->x_begmem, sizeof(char), n4, fh) / 2; // post("read chars = %d", read_chars); cvec = (char *)x->x_begmem; if(read_chars > 4) { if(strncmp(cvec, "RIFF", 4)) { post("soundfile_info_read-error: %s is no RIFF-WAVE-file", completefilename); goto sr_soundfile_info_end; } header_size += 8; // jump over RIFF chunk size cvec += 8; if(strncmp(cvec, "WAVE", 4)) { post("soundfile_info_read-error: %s is no RIFF-WAVE-file", completefilename); goto sr_soundfile_info_end; } header_size += 4; cvec += 4; for(i=header_size/2; i 32000)) { post("soundfile_info_read-error: %s has no common channel-number", completefilename); goto sr_soundfile_info_end; } SETFLOAT(x->x_at_header+SFI_HEADER_CHANNELS, (t_float)ss_ch); ch = (int)ss_ch; header_size += 2; cvec += 2; ul_sr = soundfile_info_string_to_uint32(cvec); /* samplerate */ if((ul_sr > 2000000000) || (ul_sr < 1)) { post("soundfile_info_read-error: %s has no common samplerate", completefilename); goto sr_soundfile_info_end; } ul_sr = (unsigned long)new_sr; soundfile_info_uint32_to_string(cvec, ul_sr); fseek(fh,0,SEEK_SET); read_chars = (int)fwrite (x->x_begmem, sizeof(char), n4, fh); fclose(fh); post("written"); sr = (int)ul_sr; header_size += 4; cvec += 4; header_size += 4; /* jump over bytes_per_sec */ cvec += 4; ss_bytesperframe = soundfile_info_string_to_int16(cvec); /* bytes_per_frame */ if((ss_bytesperframe < 1) || (ss_bytesperframe > 32000)) { post("soundfile_info_read-error: %s has no common number of bytes per frame", completefilename); goto sr_soundfile_info_end; } bytesperframe = (int)ss_bytesperframe; header_size += 2; cvec += 2; header_size += 2; /* jump over bits_per_sample */ cvec += 2; for(i=header_size/2; is_name[0] == '/')/*make complete path + filename*/ { strcpy(completefilename, filename->s_name); } else if(((filename->s_name[0] >= 'A')&&(filename->s_name[0] <= 'Z')|| (filename->s_name[0] >= 'a')&&(filename->s_name[0] <= 'z'))&& (filename->s_name[1] == ':')&&(filename->s_name[2] == '/')) { strcpy(completefilename, filename->s_name); } else { strcpy(completefilename, canvas_getdir(x->x_canvas)->s_name); strcat(completefilename, "/"); strcat(completefilename, filename->s_name); } fh = fopen(completefilename,"rb"); if(!fh) { post("soundfile_info_read: cannot open %s !!\n", completefilename); } else { n = x->x_mem_size; // 10000 bytes n2 = sizeof(short) * x->x_mem_size; n4 = sizeof(long) * x->x_mem_size; fseek(fh, 0, SEEK_END); filesize = ftell(fh); fseek(fh,0,SEEK_SET); read_chars = (int)fread(x->x_begmem, sizeof(char), n4, fh) / 2; fclose(fh); // post("read chars = %d", read_chars); cvec = (char *)x->x_begmem; if(read_chars > 4) { if(strncmp(cvec, "RIFF", 4)) { post("soundfile_info_read-error: %s is no RIFF-WAVE-file", completefilename); goto soundfile_info_end; } header_size += 8; // jump over RIFF chunk size cvec += 8; if(strncmp(cvec, "WAVE", 4)) { post("soundfile_info_read-error: %s is no RIFF-WAVE-file", completefilename); goto soundfile_info_end; } header_size += 4; cvec += 4; for(i=header_size/2; ix_at_header+SFI_HEADER_FORMAT_CODE, (t_float)ss_format); header_size += 2; cvec += 2; ss_ch = soundfile_info_string_to_int16(cvec); /* channels */ if((ss_ch < 1) || (ss_ch > 32000)) { post("soundfile_info_read-error: %s has no common channel-number", completefilename); goto soundfile_info_end; } SETFLOAT(x->x_at_header+SFI_HEADER_CHANNELS, (t_float)ss_ch); ch = (int)ss_ch; header_size += 2; cvec += 2; ul_sr = soundfile_info_string_to_uint32(cvec); /* samplerate */ if((ul_sr > 2000000000) || (ul_sr < 1)) { post("soundfile_info_read-error: %s has no common samplerate", completefilename); goto soundfile_info_end; } SETFLOAT(x->x_at_header+SFI_HEADER_SAMPLERATE, (t_float)ul_sr); sr = (int)ul_sr; header_size += 4; cvec += 4; header_size += 4; /* jump over bytes_per_sec */ cvec += 4; ss_bytesperframe = soundfile_info_string_to_int16(cvec); /* bytes_per_frame */ if((ss_bytesperframe < 1) || (ss_bytesperframe > 32000)) { post("soundfile_info_read-error: %s has no common number of bytes per frame", completefilename); goto soundfile_info_end; } SETFLOAT(x->x_at_header+SFI_HEADER_BYTES_PER_SAMPLE, (t_float)(ss_bytesperframe / ss_ch)); bytesperframe = (int)ss_bytesperframe; header_size += 2; cvec += 2; header_size += 2; /* jump over bits_per_sample */ cvec += 2; for(i=header_size/2; ix_at_header+SFI_HEADER_HEADERBYTES, (t_float)header_size); n_frames = (filesize - header_size) / bytesperframe; SETFLOAT(x->x_at_header+SFI_HEADER_MULTICHANNEL_FILE_LENGTH, (t_float)n_frames); SETSYMBOL(x->x_at_header+SFI_HEADER_ENDINESS, gensym("l")); SETSYMBOL(x->x_at_header+SFI_HEADER_FILENAME, gensym(completefilename)); /* post("ch = %d", ch); post("sr = %d", sr); post("bpf = %d", bytesperframe/ch); post("head = %d", header_size); post("len = %d", n_frames);*/ outlet_list(x->x_list_out, &s_list, SFI_HEADER_SIZE, x->x_at_header); soundfile_info_end: ; } } } static void soundfile_info_free(t_soundfile_info *x) { freebytes(x->x_begmem, x->x_mem_size * sizeof(long)); } static void *soundfile_info_new(void) { t_soundfile_info *x = (t_soundfile_info *)pd_new(soundfile_info_class); x->x_mem_size = SFI_HEADER_CHUNK_SIZE_ESTIMATION; /* try to read the first 10000 bytes of the soundfile */ x->x_begmem = (long *)getbytes(x->x_mem_size * sizeof(long)); x->x_list_out = outlet_new(&x->x_obj, &s_list); x->x_canvas = canvas_getcurrent(); return (x); } /* ---------------- global setup function -------------------- */ void soundfile_info_setup(void) { soundfile_info_class = class_new(gensym("soundfile_info"), (t_newmethod)soundfile_info_new, (t_method)soundfile_info_free, sizeof(t_soundfile_info), 0, 0); class_addmethod(soundfile_info_class, (t_method)soundfile_info_read, gensym("read"), A_SYMBOL, 0); class_addmethod(soundfile_info_class, (t_method)soundfile_info_overwrite_sr, gensym("overwrite_sr"), A_SYMBOL, A_FLOAT, 0); }