Files
akai-utils/third_party/akaiutil/akaiutil_wav.c
T
david 9f107b5f80 Initial commit: akai-fetch - AKAI sampler ISO downloader & extractor
- fetch: Go CLI tool for searching, downloading, and extracting
  AKAI sampler ISOs from archive.org
- scripts/extract_wavs.sh: Shell script driving akaiutil to
  convert samples to WAV
- Dockerfile: Multi-stage build packaging akaiutil + fetch
- third_party/akaiutil: Vendored akaiutil v4.6.7 source (GPLv2)
- docs/akaiutil.md: Full akaiutil reference
2026-06-15 22:33:53 -07:00

483 lines
12 KiB
C
Executable File

/*
* Copyright (C) 2010,2019 Klaus Michael Indlekofer. All rights reserved.
*
* m.indlekofer@gmx.de
*
* 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 (at your option) 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "commoninclude.h"
#include "akaiutil_wav.h"
int
wav_write_head(int outdes,
u_int datasize,u_int chnr,u_int samprate,u_int bitnr,
u_int extrasize)
{
struct wav_riffhead_s wavriffhead;
struct wav_chunkhead_s wavchunkhead;
struct wav_fmthead_s wavfmthead;
u_int drate;
/* create WAVE RIFF header */
bzero(&wavriffhead,sizeof(struct wav_riffhead_s));
bcopy(WAV_RIFFHEAD_RIFFSTR,wavriffhead.riffstr,4);
{
u_int fsize;
fsize=WAV_HEAD_SIZE-sizeof(struct wav_chunkhead_s)+datasize+extrasize;
wavriffhead.fsize[0]=0xff&fsize;
wavriffhead.fsize[1]=0xff&(fsize>>8);
wavriffhead.fsize[2]=0xff&(fsize>>16);
wavriffhead.fsize[3]=0xff&(fsize>>24);
}
bcopy(WAV_RIFFHEAD_WAVESTR,wavriffhead.wavestr,4);
/* write WAVE RIFF header */
if (WRITE(outdes,&wavriffhead,sizeof(struct wav_riffhead_s))!=sizeof(struct wav_riffhead_s)){
PRINTF_ERR("cannot write WAVE RIFF header\n");
return -1;
}
/* create FMT chunk header */
bcopy(WAV_CHUNKHEAD_FMTSTR,wavchunkhead.typestr,4);
{
u_int csize;
csize=sizeof(struct wav_fmthead_s);
wavchunkhead.csize[0]=0xff&csize;
wavchunkhead.csize[1]=0xff&(csize>>8);
wavchunkhead.csize[2]=0xff&(csize>>16);
wavchunkhead.csize[3]=0xff&(csize>>24);
}
/* write chunk header */
if (WRITE(outdes,&wavchunkhead,sizeof(struct wav_chunkhead_s))!=sizeof(struct wav_chunkhead_s)){
PRINTF_ERR("cannot write WAVE FMT header\n");
return -1;
}
/* set FMT header */
wavfmthead.ftag[0]=0xff&WAV_HEAD_FTAG_PCM;
wavfmthead.ftag[1]=0xff&(WAV_HEAD_FTAG_PCM>>8);
wavfmthead.chnr[0]=0xff&chnr;
wavfmthead.chnr[1]=0xff&(chnr>>8);
wavfmthead.srate[0]=0xff&samprate;
wavfmthead.srate[1]=0xff&(samprate>>8);
wavfmthead.srate[2]=0xff&(samprate>>16);
wavfmthead.srate[3]=0xff&(samprate>>24);
drate=chnr*samprate*(bitnr/8); /* chnr!!! */
wavfmthead.drate[0]=0xff&drate;
wavfmthead.drate[1]=0xff&(drate>>8);
wavfmthead.drate[2]=0xff&(drate>>16);
wavfmthead.drate[3]=0xff&(drate>>24);
wavfmthead.balign[0]=0xff&((bitnr/8)*chnr); /* chnr!!! */
wavfmthead.balign[1]=0xff&(((bitnr/8)*chnr)>>8); /* chnr!!! */
wavfmthead.bitnr[0]=0xff&bitnr;
wavfmthead.bitnr[1]=0xff&(bitnr>>8);
/* write WAVE FMT header */
if (WRITE(outdes,&wavfmthead,sizeof(struct wav_fmthead_s))!=sizeof(struct wav_fmthead_s)){
PRINTF_ERR("cannot write WAVE FMT header\n");
return -1;
}
/* create WAVE DATA chunk header */
bcopy(WAV_CHUNKHEAD_DATASTR,wavchunkhead.typestr,4);
wavchunkhead.csize[0]=0xff&datasize;
wavchunkhead.csize[1]=0xff&(datasize>>8);
wavchunkhead.csize[2]=0xff&(datasize>>16);
wavchunkhead.csize[3]=0xff&(datasize>>24);
/* write chunk header */
if (WRITE(outdes,&wavchunkhead,sizeof(struct wav_chunkhead_s))!=sizeof(struct wav_chunkhead_s)){
PRINTF_ERR("cannot write WAVE DATA header\n");
return -1;
}
return 0;
}
int
wav_read_head(int indes,
u_int *bcountp,
u_int *datasizep,u_int *chnrp,u_int *sampratep,u_int *bitnrp,
u_int *extrasizep,
char **errstrp)
{
struct wav_riffhead_s wavriffhead;
struct wav_chunkhead_s wavchunkhead;
struct wav_fmthead_s wavfmthead;
u_int i;
u_int bcount;
u_int remain;
u_int csize;
u_int chnr;
u_int samprate;
u_int bitnr;
bcount=0; /* no bytes read yet */
/* read WAVE RIFF header */
if (READ(indes,(char *)&wavriffhead,sizeof(struct wav_riffhead_s))!=sizeof(struct wav_riffhead_s)){
if (errstrp!=NULL){
*errstrp="read WAVE RIFF header";
}
return -1;
}
bcount+=sizeof(struct wav_riffhead_s);
/* check riffstr */
for (i=0;i<4;i++){
if (WAV_RIFFHEAD_RIFFSTR[i]!=wavriffhead.riffstr[i]){
if (errstrp!=NULL){
*errstrp="no RIFF";
}
return -1;
}
}
/* determine remaining file size */
remain=wavriffhead.fsize[0]
+(wavriffhead.fsize[1]<<8)
+(wavriffhead.fsize[2]<<16)
+(wavriffhead.fsize[3]<<24);
if (remain<sizeof(struct wav_riffhead_s)-sizeof(struct wav_chunkhead_s)){
if (errstrp!=NULL){
*errstrp="invalid file size";
}
return -1;
}
remain-=sizeof(struct wav_riffhead_s)-sizeof(struct wav_chunkhead_s);
/* check wavestr */
for (i=0;i<4;i++){
if (WAV_RIFFHEAD_WAVESTR[i]!=wavriffhead.wavestr[i]){
if (errstrp!=NULL){
*errstrp="no WAVE";
}
return -1;
}
}
/* search for fmt chunk */
for (;;){
/* read next chunk */
if (remain<sizeof(struct wav_chunkhead_s)){
if (errstrp!=NULL){
*errstrp="invalid file size";
}
return -1;
}
if (READ(indes,(char *)&wavchunkhead,sizeof(struct wav_chunkhead_s))!=sizeof(struct wav_chunkhead_s)){
if (errstrp!=NULL){
*errstrp="read WAVE FMT header";
}
return -1;
}
bcount+=sizeof(struct wav_chunkhead_s);
remain-=sizeof(struct wav_chunkhead_s);
/* get csize */
csize=wavchunkhead.csize[0]
+(wavchunkhead.csize[1]<<8)
+(wavchunkhead.csize[2]<<16)
+(wavchunkhead.csize[3]<<24);
if (remain<csize){
if (errstrp!=NULL){
*errstrp="invalid file size";
}
return -1;
}
for (i=0;i<4;i++){
if (WAV_CHUNKHEAD_FMTSTR[i]!=wavchunkhead.typestr[i]){
break; /* not fmt chunk */
}
}
if (i==4){
break; /* found fmt */
}
/* skip rest of chunk */
if (LSEEK64(indes,(OFF64_T)csize,SEEK_CUR)<0){
if (errstrp!=NULL){
*errstrp="lseek WAVE FMT header";
}
return -1;
}
bcount+=csize;
remain-=csize;
}
if (csize!=sizeof(struct wav_fmthead_s)){
if (errstrp!=NULL){
*errstrp="invalid FMT csize";
}
return -1;
}
/* read rest of fmt chunk */
if (READ(indes,(char *)&wavfmthead,sizeof(struct wav_fmthead_s))!=sizeof(struct wav_fmthead_s)){
if (errstrp!=NULL){
*errstrp="read WAVE FMT header";
}
return -1;
}
bcount+=sizeof(struct wav_fmthead_s);
remain-=sizeof(struct wav_fmthead_s);
/* check ftag */
/* XXX allow only PCM */
if ((wavfmthead.ftag[0]!=(0xff&WAV_HEAD_FTAG_PCM))
||(wavfmthead.ftag[1]!=(0xff&(WAV_HEAD_FTAG_PCM>>8)))){
if (errstrp!=NULL){
*errstrp="invalid ftag, must be PCM format";
}
return -1;
}
/* get chnr */
chnr=wavfmthead.chnr[0]
+(wavfmthead.chnr[1]<<8);
if (chnr==0){
if (errstrp!=NULL){
*errstrp="invalid chnr";
}
return -1;
}
/* set samprate */
samprate=wavfmthead.srate[0]
+(wavfmthead.srate[1]<<8)
+(wavfmthead.srate[2]<<16)
+(wavfmthead.srate[3]<<24);
/* XXX check drate: must be chnr*samprate*(bitnr/8) */
/* get bitnr */
bitnr=wavfmthead.bitnr[0]
+(wavfmthead.bitnr[1]<<8);
if (bitnr==0){
if (errstrp!=NULL){
*errstrp="invalid bitnr";
}
return -1;
}
/* XXX check balign: must be (bitnr/8)*chnr */
/* search for data chunk */
for (;;){
/* read next chunk */
if (remain<sizeof(struct wav_chunkhead_s)){
if (errstrp!=NULL){
*errstrp="invalid file size";
}
return -1;
}
if (READ(indes,(char *)&wavchunkhead,sizeof(struct wav_chunkhead_s))!=sizeof(struct wav_chunkhead_s)){
if (errstrp!=NULL){
*errstrp="read WAVE DATA header";
}
return -1;
}
bcount+=sizeof(struct wav_chunkhead_s);
remain-=sizeof(struct wav_chunkhead_s);
/* get csize */
csize=wavchunkhead.csize[0]
+(wavchunkhead.csize[1]<<8)
+(wavchunkhead.csize[2]<<16)
+(wavchunkhead.csize[3]<<24);
if (remain<csize){
if (errstrp!=NULL){
*errstrp="invalid file size";
}
return -1;
}
for (i=0;i<4;i++){
if (WAV_CHUNKHEAD_DATASTR[i]!=wavchunkhead.typestr[i]){
break; /* not data chunk */
}
}
if (i==4){
break; /* found fmt */
}
/* skip rest of chunk */
if (LSEEK64(indes,(OFF64_T)csize,SEEK_CUR)<0){
if (errstrp!=NULL){
*errstrp="lseek WAVE DATA header";
}
return -1;
}
bcount+=csize;
remain-=csize;
}
if (csize%chnr!=0){
if (errstrp!=NULL){
*errstrp="invalid DATA csize";
}
return -1;
}
if (bcountp!=NULL){
*bcountp=bcount;
}
if (datasizep!=NULL){
*datasizep=csize;
}
if (chnrp!=NULL){
*chnrp=chnr;
}
if (sampratep!=NULL){
*sampratep=samprate;
}
if (bitnrp!=NULL){
*bitnrp=bitnr;
}
if (extrasizep!=NULL){
*extrasizep=remain-csize;
}
return 0;
}
#ifndef WAV_AKAIHEAD_DISABLE
int
wav_find_akaihead(int indes,u_int *bcountp,u_int *csizep,u_int remain,u_int searchtype)
{
struct wav_chunkhead_s wavchunkhead;
u_int bcount;
u_int csize;
u_int type;
u_int i;
bcount=0; /* no bytes read yet */
csize=0; /* no chunk yet */
type=WAV_AKAIHEADTYPE_NONE; /* no AKAI header chunk found yet */
/* search for AKAI header chunk */
for (;;){
/* read next chunk */
if (remain<sizeof(struct wav_chunkhead_s)){
break;
}
if (READ(indes,(char *)&wavchunkhead,sizeof(struct wav_chunkhead_s))<0){
PRINTF_ERR("cannot read WAV chunk");
return -1;
}
bcount+=sizeof(struct wav_chunkhead_s);
remain-=sizeof(struct wav_chunkhead_s);
/* get csize */
csize=wavchunkhead.csize[0]
+(wavchunkhead.csize[1]<<8)
+(wavchunkhead.csize[2]<<16)
+(wavchunkhead.csize[3]<<24);
if (remain<csize){
break;
}
if ((searchtype==WAV_AKAIHEADTYPE_NONE)||(searchtype==WAV_AKAIHEADTYPE_SAMPLE900)){
/* check if S900 sample header chunk */
for (i=0;i<4;i++){
if (WAV_CHUNKHEAD_AKAIS900SAMPLEHEADSTR[i]!=wavchunkhead.typestr[i]){
break; /* not data chunk */
}
}
if (i==4){
/* found */
type=WAV_AKAIHEADTYPE_SAMPLE900;
break;
}
}
if ((searchtype==WAV_AKAIHEADTYPE_NONE)||(searchtype==WAV_AKAIHEADTYPE_SAMPLE1000)){
/* check if S1000 sample header chunk */
for (i=0;i<4;i++){
if (WAV_CHUNKHEAD_AKAIS1000SAMPLEHEADSTR[i]!=wavchunkhead.typestr[i]){
break; /* not data chunk */
}
}
if (i==4){
/* found */
type=WAV_AKAIHEADTYPE_SAMPLE1000;
break;
}
}
if ((searchtype==WAV_AKAIHEADTYPE_NONE)||(searchtype==WAV_AKAIHEADTYPE_SAMPLE3000)){
/* check if S3000 sample header chunk */
for (i=0;i<4;i++){
if (WAV_CHUNKHEAD_AKAIS3000SAMPLEHEADSTR[i]!=wavchunkhead.typestr[i]){
break; /* not data chunk */
}
}
if (i==4){
/* found */
type=WAV_AKAIHEADTYPE_SAMPLE3000;
break;
}
}
if ((searchtype==WAV_AKAIHEADTYPE_NONE)||(searchtype==WAV_AKAIHEADTYPE_DDTAKE)){
/* check if DD take header chunk */
for (i=0;i<4;i++){
if (WAV_CHUNKHEAD_AKAIDDTAKEHEADSTR[i]!=wavchunkhead.typestr[i]){
break; /* not data chunk */
}
}
if (i==4){
/* found */
type=WAV_AKAIHEADTYPE_DDTAKE;
break;
}
}
/* skip rest of chunk */
if (LSEEK64(indes,(OFF64_T)csize,SEEK_CUR)<0){
PERROR("cannot lseek WAV chunk");
return -1;
}
bcount+=csize;
remain-=csize;
}
if (type==WAV_AKAIHEADTYPE_NONE){ /* no AKAI header chunk found? */
csize=0;
}
if (bcountp!=NULL){
*bcountp=bcount;
}
if (csizep!=NULL){
*csizep=csize;
}
return (int)type;
}
#endif
/* EOF */