/* Note: the old versions of the peak info functions copy peak stats from the file header in memory into the sfm[fno] array maintained in sound.c. This seems unnecessary, since both are initialized on opening any file and updated on endnote. When would they ever be different from the perspective of these info functions, which can't be called from Minc in the *middle* of an instrument run? Are they also called internally, like m_dur? -JGG */ double m_peak(float p[], int n_args) { int n, fno; float peak, chanpeak; fno = (int) p[0]; if (!isopen[fno]) { fprintf(stderr, "You haven't opened file %d yet!\n", fno); closesf(); } peak = 0.0; if (sfmaxamptime(&sfm[fno]) > 0L) { for (n = 0; n < sfchans(&sfdesc[fno]); n++) { chanpeak = sfmaxamp(&sfm[fno], n); if (chanpeak > peak) peak = chanpeak; } } else fprintf(stderr, "File %d has no peak stats!\n", fno); return peak; }
double resetamp(float p[], int n_args) { int i; int fno; fno = p[0]; if(!isopen[fno]) { printf("File number %d has not been opened\n",fno); return -1.0; } for(i = 0; i<sfchans(&sfdesc[fno]); i++) { sfmaxamp(&sfm[fno],i) = 0; sfmaxamploc(&sfm[fno],i) = 0; } if((filepointer[fno] = lseek(sfd[fno],0L,0)) < 0) { fprintf(stderr,"Bad lseek to beginning of file\n"); perror("lseek"); closesf(); } putsfcode(&sfdesc[fno],(char *)&sfm[fno],&code); if(wheader(sfd[fno],(char *)&sfdesc[fno])) { fprintf(stderr,"Bad header write\n"); perror("write"); closesf(); } printf("reset header amplitudes to 0 in file %d\n",fno); return 0.0; }
float getpeakval(float peakflag, int fno) { float opeak; int i; float *pk; pk = (float *)peak[fno]; if(peakflag < 0) { for(i=0,opeak=0; i<sfchans(&sfdesc[fno]); i++) if(pk[i] > opeak) opeak=pk[i]; } else if(peakflag == 0) { for(i=0,opeak=0; i<sfchans(&sfdesc[fno]); i++) if((float)sfmaxamp(&sfm[fno],i) > opeak) opeak=sfmaxamp(&sfm[fno],i); } else opeak = peakflag; /* printf("peakflag=%f, peakval=%f\n",peakflag,opeak); */ return(opeak); }
double m_right(float p[], int n_args) { int fno; fno = (int) p[0]; if (!isopen[fno]) { fprintf(stderr, "You haven't opened file %d yet!\n", fno); closesf(); } if (sfmaxamptime(&sfm[fno]) > 0L) return (sfmaxamp(&sfm[fno], 1)); /* for channel 1 */ else fprintf(stderr, "File %d has no peak stats!\n", fno); return 0.0; }
int endnote(int xno) { struct timeval tp; struct timezone tzp; int i,j,final_bytes,fno; float notepeak,*pk; double total; long *pkloc; struct tms timbuf; float peakval; struct stat st; short tisamp,*tibuf; float tfsamp,*tfbuf; fno = ABS(xno); /* if fno is negative it means don't write final buffer,just pretend to */ if(wipe_is_off[fno]) _backup(fno); /* else _flushbuf(fno); */ if(!peakoff[fno]) _chkpeak(fno); final_bytes = pointer[fno] * sfclass(&sfdesc[fno]); /* This was DS's and PL's version of real time */ /* Not used in this version */ #ifdef OLDRT /* SHOULD NOT PLAY HERE -- LAST BUFFERS ALREADY PLAYED */ if ((sfclass(&sfdesc[fno]) == SF_SHORT) && play_is_on) playbuf(sndbuf[fno],final_bytes/SF_SHORT); else if ((sfclass(&sfdesc[fno]) == SF_FLOAT) && play_is_on) { peakval = getpeakval(peakflag,fno); playfbuf(sndbuf[fno],peakval,swap[fno],nbytes/SF_FLOAT); } #endif /* write out only fractional part of last record, god bless unix!*/ if(pointer[fno] && (play_is_on < 2)) { if(xno >= 0) { /* Swap bytes if necessary */ if(final_bytes && swap_bytes[fno]) { /* SHORT file */ if(sfclass(&sfdesc[fno]) == SF_SHORT) { tibuf = (short *)sndbuf[fno]; for (i=0;i<final_bytes/SF_SHORT;i++) { tisamp = *(tibuf+i); *(tibuf+i) = reverse_int2(&tisamp); } } /* FLOAT file */ if(sfclass(&sfdesc[fno]) == SF_FLOAT) { tfbuf = (float *)sndbuf[fno]; for (i=0;i<final_bytes/SF_FLOAT;i++) { /* byte_reverse4(tfbuf+i); */ /* tfsamp = *(tfbuf+i); */ /* *(tfbuf+i) = (float)reverse_int4(&tfsamp); */ tfsamp = *(tfbuf+i); byte_reverse4(&tfsamp); *(tfbuf+i) = tfsamp; } } } if((i = write(sfd[fno],sndbuf[fno],final_bytes)) != final_bytes) { rtcmix_warn("CMIX", "Bad UNIX write, file %d, nbytes = %d\n", fno,i); perror("write"); closesf(); } } if((filepointer[fno] += final_bytes) > originalsize[fno]) if(xno >0) originalsize[fno] = filepointer[fno]; } /* DT: if(play_is_on) flush_buffers(); */ pk = (float *)peak[fno]; pkloc = (long *)peakloc[fno]; total = ((double)filepointer[fno]-headersize[fno]) /((double)sfclass(&sfdesc[fno])) /(double)sfchans(&sfdesc[fno])/SR(); /* _writeit(fno); write out final record */ for(i = 0,notepeak=0; i<sfchans(&sfdesc[fno]); i++) { if(*(pk+i) > sfmaxamp(&sfm[fno],i)) { sfmaxamp(&sfm[fno],i) = *(pk+i); sfmaxamploc(&sfm[fno],i) = *(pkloc+i); } if(*(pk+i) > notepeak) notepeak = *(pk+i); } gettimeofday(&tp,&tzp); sfmaxamptime(&sfm[fno]) = tp.tv_sec; if((filepointer[fno] = lseek(sfd[fno],0L,0)) < 0) { rtcmix_warn("CMIX", "Bad lseek to beginning of file\n"); perror("lseek"); closesf(); } times(&timbuf); #ifndef MAXMSP // this really isn't used... printf("\n(%6.2f)",(float)( (timbuf.tms_stime-clockin[fno].tms_stime)+ (timbuf.tms_utime-clockin[fno].tms_utime))/60.); printf(" %9.4f .. %9.4f MM ",starttime[fno],total); if(!peakoff[fno]) { for(j=0;j<sfchans(&sfdesc[fno]);j++) printf(" c%d=%e",j,*(pk+j)); printf("\n"); if(punch[fno]) { printf("alter(%e,%e,%e/%e", (double)starttime[fno],(double)(total-starttime[fno]), punch[fno],notepeak); for(i=0; i<sfchans(&sfdesc[fno]); i++) printf(",1 "); printf(")\n"); printf("mix(%g,%g,%g,%g/%g", (double)starttime[fno],(double)starttime[fno],-(double)(total-starttime[fno]),punch[fno],notepeak); for(i=0; i<sfchans(&sfdesc[fno]); i++) printf(",%d ",i); printf(")\n"); } } #endif // MAXMSP /* Copy the updated peak stats into the SFHEADER struct for this output file. (No swapping necessary.) */ memcpy(&(sfmaxampstruct(&sfdesc[fno])), &sfm[fno], sizeof(SFMAXAMP)); /* Write header to file. */ if (wheader(sfd[fno], &sfdesc[fno])) { rtcmix_warn("endnote", "bad header write\n"); perror("write"); closesf(); } return 0; }
double m_open(float *p, short n_args, double *pp) { char *name,*cp,*getsfcode(); int fno,i,inew; float *opk; name = DOUBLE_TO_STRING(pp[0]); fno = p[1]; // JGG: will name ptr be valid for entire program run? Is its memory held by // parser? If not, we should malloc sfname[fno] below (with other mallocs) sfname[fno] = name; status[fno] = (n_args == 3) ? (int)p[2] : 2; if((fno >= NFILES) || (fno < 0)) { rtcmix_warn("m_open", "Only %d files allowed\n", NFILES); closesf(); } inew = 0; if(isopen[fno]) { close(sfd[fno]); } else inew = 1; istape[fno] = (n_args == 4) ? 1 : 0; /* in the case of a tape, there will be a 4th argument listing the file number */ rwopensf(name,sfd[fno],sfdesc[fno],sfst[fno],"CMIX",i,status[fno]); if (i < 0) closesf(); if (status[fno] == O_RDWR && !WRITEABLE_HEADER_TYPE(sfheadertype(&sfdesc[fno]))) { rtcmix_warn("m_open", "can't write this type of header.\n"); closesf(); } isopen[fno] = 1; swap_bytes[fno] = swap; /* swap and isNext set in rwopensf */ is_Next[fno] = isNext; headersize[fno] = getheadersize(&sfdesc[fno]); rtcmix_advise(NULL, "name: %s sr: %.3f nchans: %d class: %d\n",name, sfsrate(&sfdesc[fno]),sfchans(&sfdesc[fno]), sfclass(&sfdesc[fno])); rtcmix_advise(NULL, "Soundfile type: %s\n", mus_header_type_name(sfheadertype(&sfdesc[fno]))); rtcmix_advise(NULL, " data format: %s\n", mus_data_format_name(sfdataformat(&sfdesc[fno]))); rtcmix_advise(NULL, "Duration of file is %f seconds.\n", (float)(sfst[fno].st_size - headersize[fno])/(float)sfclass(&sfdesc[fno])/(float)sfchans(&sfdesc[fno])/sfsrate(&sfdesc[fno])); originalsize[fno] = istape[fno] ? 999999999 : sfst[fno].st_size; /* sfstats(sfd[fno]); */ if(inew) { if((sndbuf[fno] = (char *)malloc((unsigned)nbytes)) == NULL) { rtcmix_warn("CMIX", "malloc sound buffer error\n"); closesf(); } if((peakloc[fno] = (char *)malloc((unsigned)(sfchans(&sfdesc[fno]) * LONG))) == NULL) { rtcmix_warn("CMIX", "malloc ovpeak buffer error\n"); closesf(); } if((peak[fno] = (char *)malloc((unsigned)(sfchans(&sfdesc[fno])* FLOAT))) == NULL) { rtcmix_warn("CMIX", "malloc peak buffer error!\n"); closesf(); } peakoff[fno] = 0; /* default to peakcheckon when opening file*/ punch[fno] = 0; /* default to no punch when opening file*/ } if(sfclass(&sfdesc[fno]) == SHORT) { addoutpointer[fno] = _iaddout; layoutpointer[fno] = _ilayout; wipeoutpointer[fno] = _iwipeout; getinpointer[fno] = _igetin; } else { addoutpointer[fno] = _faddout; layoutpointer[fno] = _flayout; wipeoutpointer[fno] = _fwipeout; getinpointer[fno] = _fgetin; } if(!SR()) set_SR(sfsrate(&sfdesc[fno])); if(sfsrate(&sfdesc[fno])!= SR()) rtcmix_advise("CMIX", "Note--> SR reset to %f\n",SR()); /* read in former peak amplitudes, make sure zero'ed out to start.*/ /* In the sndlib version, we store peak stats differently. See comments in sndlibsupport.c for an explanation. The sndlib version of rwopensf reads peak stats, so here we just have to copy these into the sfm[fno] array. (No swapping necessary.) */ memcpy(&sfm[fno], &(sfmaxampstruct(&sfdesc[fno])), sizeof(SFMAXAMP)); for(opk = (float *)peak[fno], i = 0; i<sfchans(&sfdesc[fno]); i++) *(opk+i) = sfmaxamp(&sfm[fno],i); bufsize[fno] = nbytes / sfclass(&sfdesc[fno]);/* set size in words */ return 0.0; }
double m_clean(float p[], int n_args) /* a fast clean of file, after header */ { /* if p1-> = 0, clean whole file, else skip=p1, dur=p2, ch-on? p3--> */ int i; off_t n, nwrite, todo; char *point; int fno,segment,chlist[4]; int skipbytes; fno = (int) p[0]; skipbytes = 0; if(!status[fno]) { rtcmix_warn(NULL,"fno %d is write-protected!\n",fno); closesf(); } todo = originalsize[fno] - headersize[fno]; segment = (n_args > 1) ? 1 : 0; if(segment) { skipbytes = (p[1] > 0) ? p[1] * sfclass(&sfdesc[fno]) * SR() * sfchans(&sfdesc[fno]) : -p[1] * sfclass(&sfdesc[fno]) * sfchans(&sfdesc[fno]); todo = (p[2] > 0) ? p[2] * sfclass(&sfdesc[fno]) * SR() * sfchans(&sfdesc[fno]) : -p[2] * sfclass(&sfdesc[fno]) * sfchans(&sfdesc[fno]); for(i=0; i<sfchans(&sfdesc[fno]); i++) chlist[i] = p[i+3]; } point = (char *)sndbuf[fno]; if(!segment) for(i=0; i<nbytes; i++) *(point+i) = 0; if((filepointer[fno] = lseek(sfd[fno],skipbytes+headersize[fno],0)) == -1) { rtcmix_warn("CMIX", "bad sflseek in clean\n"); closesf(); } #ifdef MINGW // no %11 in Win libc, have to use %I64 instead: // http://stackoverflow.com/questions/13590735/printf-long-long-int-in-c-with-gcc? printf("Clean %I64d bytes\n",(long long)todo); #else printf("Clean %lld bytes\n",(long long)todo); #endif while(todo) { nwrite = (todo > nbytes) ? nbytes : todo; if(segment) { if((n = read(sfd[fno],sndbuf[fno],nwrite)) == 0) { /* allow for fractional reads*/ fprintf(stderr, "CMIX: Apparent eof in clean\n"); return -1.0; } if(lseek(sfd[fno],-n,1) < 0) { fprintf(stderr,"Bad UNIX lseek in clean\n"); closesf(); } m_zapout(fno,sndbuf[fno],n,chlist); nwrite = n; } if((n = write(sfd[fno],sndbuf[fno],nwrite)) == 0) { fprintf(stderr, "CMIX: Apparent eof in clean\n"); closesf(); } todo -= n; } if(!segment) { if((lseek(sfd[fno],0,0)) == -1) { fprintf(stderr,"CMIX: bad lseek in clean\n"); closesf(); } for(i = 0; i<sfchans(&sfdesc[fno]); i++) { sfmaxamp(&sfm[fno],i) = 0; sfmaxamploc(&sfm[fno],i) = 0; } putsfcode(&sfdesc[fno],(char *)&sfm[fno],&code); if(wheader(sfd[fno],(char *)&sfdesc[fno])) { fprintf(stderr,"Bad header write\n"); perror("write"); closesf(); } } else if((lseek(sfd[fno],headersize[fno],0)) == -1) { fprintf(stderr,"CMIX: bad lseek in clean\n"); closesf(); } filepointer[fno] = headersize[fno]; printf("Clean successfully finished.\n"); return 0.0; }
int main(int argc, char *argv[]) { int sf; int comment = 0; struct stat sfst; SFHEADER sfh; SFMAXAMP sfm; SFCOMMENT sfcm; SFCODE *sizer; FILE *fcom; char *sfname,*cp,*getsfcode(); int length,newchans,newclass,newpeak,result,i,n,tfd,tn,nchars=MINCOMM; float newsrate; int zap; zap = newchans = newclass = newsrate = newpeak = 0; length = 1; if(argc > 1) { if(*argv[1] != '-') { printf("usage: \"sfhedit -r [srate] -[i=int;f=float] -c [nchans] -p [peak] -w [comment] -z\"\n"); exit(1); } } else if(argc == 1) { printf("usage: \"sfhedit -r [srate] -[i=int;f=float] -c [nchans] -p [peak] -w [comment] -z\"\n"); exit(1); } while((*++argv)[0] == '-') { argc -= 2; /* Take away two args */ for(cp = argv[0]+1; *cp; cp++) { switch(*cp) { /* Grap options */ case 'r': newsrate = atof(*++argv); break; case 'i': newclass = SF_SHORT; break; case 'f': newclass = SF_FLOAT; break; case 'c': newchans = atoi(*++argv); if(newchans > 4) { printf(" Sorry, maximum is 4 channels\n"); exit(1); } break; case 'p': newpeak = 1; break; case 'w': comment = 1; break; case 'z': zap = 1; break; case 'l': length = 1; break; default: printf("don't know about option %c\n",*cp); } } } sfname = argv[0]; rwopensf(sfname,sf,sfh,sfst,"sfhedit",result,2); if(result < 0) { exit(1); } printsf(&sfh); if(newchans) { sfchans(&sfh) = newchans; printf("-->Channels reset to %d\n",newchans); } if(newsrate) { sfsrate(&sfh) = newsrate; printf("-->Sampling rate reset to %5.0f\n",newsrate); } if(newclass) { sfclass(&sfh) = newclass; printf("-->Class reset to %d\n",newclass); } if(newpeak) { for(i=0; i<sfchans(&sfh); i++) { printf("Enter peak and time for channel %d\t",i); scanf("%f %ld",&sfmaxamp(&sfm,i),&sfmaxamploc(&sfm,i)); } sfmaxamptime(&sfm) = time(NULL); putsfcode(&sfh,(char *)&sfm,&code); } if(zap) { if(ftruncate(sf,0) < 0) printf("Bad truncation\n"); for(i=0; i<sfchans(&sfh); i++) { sfmaxamp(&sfm,i) = sfmaxamploc(&sfm,i) = 0; putsfcode(&sfh,(char *)&sfm,&code); putlength(sfname,sf,&sfh); } printf("file truncated to 0, and header adjusted\n"); } if(comment) { cp = getsfcode(&sfh,SF_COMMENT); if(cp == NULL) { printf("No comment found. Adding a new one..\n"); system("vi /tmp/comment"); fcom = fopen("/tmp/comment","r"); i=0; while ( (sfcomm(&sfcm,i) = getc(fcom)) != EOF ) { if (++i > MAXCOMM) { printf("Gimme a break! I can only take %d characters\n",MAXCOMM); printf("comment truncated to %d characters\n",MAXCOMM); commentcode.bsize = MAXCOMM + sizeof(SFCODE); break; } } sfcomm(&sfcm,i) = '\0'; system("rm /tmp/comment"); if (nchars > MINCOMM) commentcode.bsize = nchars + sizeof(SFCODE); if (i > nchars) commentcode.bsize = i + sizeof(SFCODE); if (putsfcode(&sfh,(char *)&sfcm,&commentcode) < 0) { printf("comment didn't get written, sorry!\n"); exit(1); } goto skip; } strncpy((char *)&sfcm, sfcommentstr(&sfh), MAXCOMM - 1); sfcm.comment[MAXCOMM - 1] = '\0'; tfd = open("/tmp/tmpcom",O_CREAT|O_RDWR,0644); tn = write(tfd, &sfcomm(&sfcm,0), strlen(&sfcomm(&sfcm,0))); close(tfd); system("vi /tmp/tmpcom"); tfd = open("/tmp/tmpcom",0); n = read(tfd,&sfcomm(&sfcm,0),MAXCOMM); system("rm /tmp/tmpcom"); if (n < tn) { for (i = n; i <= tn; i++) { sfcomm(&sfcm,i) = '\0'; } } if (putsfcode(&sfh,(char *)&sfcm,&commentcode) < 0) { printf("comment didn't get written, sorry!\n"); exit(1); } } skip: lseek(sf,0,0); if(wheader(sf,(char *)&sfh)) { printf("Can't seem to write header on file %s\n",sfname); perror("main"); exit(1); } if (length) { /* do this last, after wheader */ putlength(sfname,sf,&sfh); } return 0; }