📄 wav.c
字号:
case SF_FORMAT_ALAW : wavex_write_guid (psf, &MSGUID_SUBTYPE_ALAW) ; add_fact_chunk = SF_TRUE ; break ; case SF_FORMAT_MS_ADPCM : /* todo, GUID exists */ default : return SFE_UNIMPLEMENTED ; } ; if (add_fact_chunk) psf_binheader_writef (psf, "etm48", fact_MARKER, 4, psf->sf.frames) ; if (psf->str_flags & SF_STR_LOCATE_START) wav_write_strings (psf, SF_STR_LOCATE_START) ; if (psf->has_peak && psf->peak_loc == SF_PEAK_START) { psf_binheader_writef (psf, "em4", PEAK_MARKER, sizeof (PEAK_CHUNK) + psf->sf.channels * sizeof (PEAK_POS)) ; psf_binheader_writef (psf, "e44", 1, time (NULL)) ; for (k = 0 ; k < psf->sf.channels ; k++) psf_binheader_writef (psf, "ef4", psf->pchunk->peaks [k].value, psf->pchunk->peaks [k].position) ; } ; psf_binheader_writef (psf, "etm8", data_MARKER, psf->datalength) ; psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; psf->dataoffset = psf->headindex ; if (current < psf->dataoffset) psf_fseek (psf, psf->dataoffset, SEEK_SET) ; else if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ;} /* wavex_write_header */static intwav_write_tailer (SF_PRIVATE *psf){ int k ; /* Reset the current header buffer length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; psf->dataend = psf_fseek (psf, 0, SEEK_END) ; /* Add a PEAK chunk if requested. */ if (psf->has_peak && psf->peak_loc == SF_PEAK_END) { psf_binheader_writef (psf, "em4", PEAK_MARKER, sizeof (PEAK_CHUNK) + psf->sf.channels * sizeof (PEAK_POS)) ; psf_binheader_writef (psf, "e44", 1, time (NULL)) ; for (k = 0 ; k < psf->sf.channels ; k++) psf_binheader_writef (psf, "ef4", psf->pchunk->peaks [k].value, psf->pchunk->peaks [k].position) ; } ; if (psf->str_flags & SF_STR_LOCATE_END) wav_write_strings (psf, SF_STR_LOCATE_END) ; /* Write the tailer. */ if (psf->headindex > 0) psf_fwrite (psf->header, psf->headindex, 1, psf) ; return 0 ;} /* wav_write_tailer */static voidwav_write_strings (SF_PRIVATE *psf, int location){ int k, prev_head_index, saved_head_index ; prev_head_index = psf->headindex + 4 ; psf_binheader_writef (psf, "em4m", LIST_MARKER, 0xBADBAD, INFO_MARKER) ; for (k = 0 ; k < SF_MAX_STRINGS ; k++) { if (psf->strings [k].type == 0) break ; if (psf->strings [k].flags != location) continue ; switch (psf->strings [k].type) { case SF_STR_SOFTWARE : psf_binheader_writef (psf, "ems", ISFT_MARKER, psf->strings [k].str) ; break ; case SF_STR_TITLE : psf_binheader_writef (psf, "ems", INAM_MARKER, psf->strings [k].str) ; break ; case SF_STR_COPYRIGHT : psf_binheader_writef (psf, "ems", ICOP_MARKER, psf->strings [k].str) ; break ; case SF_STR_ARTIST : psf_binheader_writef (psf, "ems", IART_MARKER, psf->strings [k].str) ; break ; case SF_STR_COMMENT : psf_binheader_writef (psf, "ems", ICMT_MARKER, psf->strings [k].str) ; break ; case SF_STR_DATE : psf_binheader_writef (psf, "ems", ICRD_MARKER, psf->strings [k].str) ; break ; } ; } ; saved_head_index = psf->headindex ; psf->headindex = prev_head_index ; psf_binheader_writef (psf, "e4", saved_head_index - prev_head_index - 4) ; psf->headindex = saved_head_index ;} /* wav_write_strings */static intwav_close (SF_PRIVATE *psf){ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { wav_write_tailer (psf) ; if ((psf->sf.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV) wav_write_header (psf, SF_TRUE) ; else wavex_write_header (psf, SF_TRUE) ; } ; return 0 ;} /* wav_close */static intwav_command (SF_PRIVATE *psf, int command, void *data, int datasize){ /* Avoid compiler warnings. */ psf = psf ; data = data ; datasize = datasize ; switch (command) { default : break ; } ; return 0 ;} /* wav_command */static intwav_subchunk_parse (SF_PRIVATE *psf, int chunk){ sf_count_t current_pos ; char *cptr ; int dword, bytesread, length ; current_pos = psf_fseek (psf, 0, SEEK_CUR) ; bytesread = psf_binheader_readf (psf, "e4", &length) ; if (current_pos + length > psf->filelength) { psf_log_printf (psf, "%M : %d (should be %d)\n", chunk, length, (int) (psf->filelength - current_pos)) ; length = psf->filelength - current_pos ; } else psf_log_printf (psf, "%M : %d\n", chunk, length) ; while (bytesread < length) { bytesread += psf_binheader_readf (psf, "m", &chunk) ; switch (chunk) { case adtl_MARKER : case INFO_MARKER : /* These markers don't contain anything. */ psf_log_printf (psf, " %M\n", chunk) ; break ; case data_MARKER: psf_log_printf (psf, " %M inside a LIST block??? Backing out.\n", chunk) ; /* Jump back four bytes and return to caller. */ psf_binheader_readf (psf, "j", -4) ; return 0 ; case ISFT_MARKER : case ICOP_MARKER : case IARL_MARKER : case IART_MARKER : case ICMT_MARKER : case ICRD_MARKER : case IENG_MARKER : case INAM_MARKER : case IPRD_MARKER : case ISBJ_MARKER : case ISRC_MARKER : bytesread += psf_binheader_readf (psf, "e4", &dword) ; dword += (dword & 1) ; if (dword > SIGNED_SIZEOF (psf->u.cbuf)) { psf_log_printf (psf, " *** %M : %d (too big)\n", chunk, dword) ; return SFE_INTERNAL ; } ; cptr = psf->u.cbuf ; psf_binheader_readf (psf, "b", cptr, dword) ; bytesread += dword ; cptr [dword - 1] = 0 ; psf_log_printf (psf, " %M : %s\n", chunk, cptr) ; break ; case labl_MARKER : { int mark_id ; bytesread += psf_binheader_readf (psf, "e44", &dword, &mark_id) ; dword -= 4 ; dword += (dword & 1) ; if (dword > SIGNED_SIZEOF (psf->u.cbuf)) { psf_log_printf (psf, " *** %M : %d (too big)\n", chunk, dword) ; return SFE_INTERNAL ; } ; cptr = psf->u.cbuf ; psf_binheader_readf (psf, "b", cptr, dword) ; bytesread += dword ; cptr [dword - 1] = 0 ; psf_log_printf (psf, " %M : %d : %s\n", chunk, mark_id, cptr) ; } ; break ; case DISP_MARKER : case ltxt_MARKER : case note_MARKER : bytesread += psf_binheader_readf (psf, "e4", &dword) ; dword += (dword & 1) ; psf_binheader_readf (psf, "j", dword) ; bytesread += dword ; psf_log_printf (psf, " %M : %d\n", chunk, dword) ; break ; default : psf_binheader_readf (psf, "e4", &dword) ; bytesread += sizeof (dword) ; dword += (dword & 1) ; psf_binheader_readf (psf, "j", dword) ; bytesread += dword ; psf_log_printf (psf, " *** %M : %d\n", chunk, dword) ; if (dword > length) return 0 ; break ; } ; switch (chunk) { case ISFT_MARKER : psf_store_string (psf, SF_STR_SOFTWARE, psf->u.cbuf) ; break ; case ICOP_MARKER : psf_store_string (psf, SF_STR_COPYRIGHT, psf->u.cbuf) ; break ; case INAM_MARKER : psf_store_string (psf, SF_STR_TITLE, psf->u.cbuf) ; break ; case IART_MARKER : psf_store_string (psf, SF_STR_ARTIST, psf->u.cbuf) ; break ; case ICMT_MARKER : psf_store_string (psf, SF_STR_COMMENT, psf->u.cbuf) ; break ; case ICRD_MARKER : psf_store_string (psf, SF_STR_DATE, psf->u.cbuf) ; break ; } ; if (psf->logindex >= SIGNED_SIZEOF (psf->logbuffer) - 2) return SFE_LOG_OVERRUN ; } ; current_pos = psf_fseek (psf, 0, SEEK_CUR) - current_pos ; if (current_pos - 4 != length) psf_log_printf (psf, "**** Bad chunk length %d sbould be %D\n", length, current_pos - 4) ; return 0 ;} /* wav_subchunk_parse */static intwav_read_smpl_chunk (SF_PRIVATE *psf, unsigned int chunklen){ unsigned int bytesread = 0, dword, sampler_data, loop_count ; int k ; chunklen += (chunklen & 1) ; bytesread += psf_binheader_readf (psf, "e4", &dword) ; psf_log_printf (psf, " Manufacturer : %X\n", dword) ; bytesread += psf_binheader_readf (psf, "e4", &dword) ; psf_log_printf (psf, " Product : %u\n", dword) ; bytesread += psf_binheader_readf (psf, "e4", &dword) ; psf_log_printf (psf, " Period : %u nsec\n", dword) ; bytesread += psf_binheader_readf (psf, "e4", &dword) ; psf_log_printf (psf, " Midi Note : %u\n", dword) ; bytesread += psf_binheader_readf (psf, "e4", &dword) ; if (dword != 0) { LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), "%f", (1.0 * 0x80000000) / ((unsigned int) dword)) ; psf_log_printf (psf, " Pitch Fract. : %s\n", psf->u.cbuf) ; } else psf_log_printf (psf, " Pitch Fract. : 0\n") ; bytesread += psf_binheader_readf (psf, "e4", &dword) ; psf_log_printf (psf, " SMPTE Format : %u\n", dword) ; bytesread += psf_binheader_readf (psf, "e4", &dword) ; LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), "%02d:%02d:%02d %02d", (dword >> 24) & 0x7F, (dword >> 16) & 0x7F, (dword >> 8) & 0x7F, dword & 0x7F) ; psf_log_printf (psf, " SMPTE Offset : %s\n", psf->u.cbuf) ; bytesread += psf_binheader_readf (psf, "e4", &loop_count) ; psf_log_printf (psf, " Loop Count : %u\n", loop_count) ; /* Sampler Data holds the number of data bytes after the CUE chunks which ** is not actually CUE data. Display value after CUE data. */ bytesread += psf_binheader_readf (psf, "e4", &sampler_data) ; while (loop_count > 0 && chunklen - bytesread >= 24) { bytesread += psf_binheader_readf (psf, "e4", &dword) ; psf_log_printf (psf, " Cue ID : %2u", dword) ; bytesread += psf_binheader_readf (psf, "e4", &dword) ; psf_log_printf (psf, " Type : %2u", dword) ; bytesread += psf_binheader_readf (psf, "e4", &dword) ; psf_log_printf (psf, " Start : %5u", dword) ; bytesread += psf_binheader_readf (psf, "e4", &dword) ; psf_log_printf (psf, " End : %5u", dword) ; bytesread += psf_binheader_readf (psf, "e4", &dword) ; psf_log_printf (psf, " Fraction : %5u", dword) ; bytesread += psf_binheader_readf (psf, "e4", &dword) ; psf_log_printf (psf, " Count : %5u\n", dword) ; loop_count -- ; } ; if (chunklen - bytesread == 0) { if (sampler_data != 0) psf_log_printf (psf, " Sampler Data : %u (should be 0)\n", sampler_data) ; else psf_log_printf (psf, " Sampler Data : %u\n", sampler_data) ; } else { if (sampler_data != chunklen - bytesread) { psf_log_printf (psf, " Sampler Data : %u (should have been %u)\n", sampler_data, chunklen - bytesread) ; sampler_data = chunklen - bytesread ; } else psf_log_printf (psf, " Sampler Data : %u\n", sampler_data) ; psf_log_printf (psf, " ") ; for (k = 0 ; k < (int) sampler_data ; k++) { char ch ; if (k > 0 && (k % 20) == 0) psf_log_printf (psf, "\n ") ; bytesread += psf_binheader_readf (psf, "1", &ch) ; psf_log_printf (psf, "%02X ", ch & 0xFF) ; } ; psf_log_printf (psf, "\n") ; } ; return 0 ;} /* wav_read_smpl_chunk *//*** The acid chunk goes a little something like this:**** 4 bytes 'acid'** 4 bytes (int) length of chunk starting at next byte**** 4 bytes (int) type of file:** this appears to be a bit mask,however some combinations** are probably impossible and/or qualified as "errors"**** 0x01 On: One Shot Off: Loop** 0x02 On: Root note is Set Off: No root** 0x04 On: Stretch is On, Off: Strech is OFF** 0x08 On: Disk Based Off: Ram based** 0x10 On: ?????????? Off: ????????? (Acidizer puts that ON)**** 2 bytes (short) root note** if type 0x10 is OFF : [C,C#,(...),B] -> [0x30 to 0x3B]** if type 0x10 is ON : [C,C#,(...),B] -> [0x3C to 0x47]** (both types fit on same MIDI pitch albeit different octaves, so who cares)**** 2 bytes (short) ??? always set to 0x8000** 4 bytes (float) ??? seems to be always 0** 4 bytes (int) number of beats** 2 bytes (short) meter denominator //always 4 in SF/ACID** 2 bytes (short) meter numerator //always 4 in SF/ACID** //are we sure about the order?? usually its num/denom** 4 bytes (float) tempo***/static intwav_read_acid_chunk (SF_PRIVATE *psf, unsigned int chunklen){ unsigned int bytesread = 0 ; int beats, flags ; short rootnote, q1, meter_denom, meter_numer ; float q2, tempo ; chunklen += (chunklen & 1) ; bytesread += psf_binheader_readf (psf, "e422f", &flags, &rootnote, &q1, &q2) ; LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), "%f", q2) ; psf_log_printf (psf, " Flags : 0x%04x (%s,%s,%s,%s,%s)\n", flags, (flags & 0x01) ? "OneShot" : "Loop", (flags & 0x02) ? "RootNoteValid" : "RootNoteInvalid", (flags & 0x04) ? "StretchOn" : "StretchOff", (flags & 0x08) ? "DiskBased" : "RAMBased", (flags & 0x10) ? "??On" : "??Off") ; psf_log_printf (psf, " Root note : 0x%x\n ???? : 0x%04x\n ???? : %s\n", rootnote, q1, psf->u.cbuf) ; bytesread += psf_binheader_readf (psf, "e422f", &beats, &meter_denom, &meter_numer, &tempo) ; LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), "%f", tempo) ; psf_log_printf (psf, " Beats : %d\n Meter : %d/%d\n Tempo : %s\n", beats, meter_numer, meter_denom, psf->u.cbuf) ; psf_binheader_readf (psf, "j", chunklen - bytesread) ; if ((psf->loop_info = calloc (1, sizeof (SF_LOOP_INFO))) == NULL) return SFE_MALLOC_FAILED ; psf->loop_info->time_sig_num = meter_numer ; psf->loop_info->time_sig_den = meter_denom ; psf->loop_info->loop_mode = (flags & 0x01) ? SF_LOOP_NONE : SF_LOOP_FORWARD ; psf->loop_info->num_beats = beats ; psf->loop_info->bpm = tempo ; psf->loop_info->root_key = (flags & 0x02) ? rootnote : -1 ; return 0 ;} /* wav_read_acid_chunk *//*** Do not edit or modify anything in this comment block.** The arch-tag line is a file identity tag for the GNU Arch** revision control system.**** arch-tag: 9c551689-a1d8-4905-9f56-26a204374f18*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -