hi erik,
i've got another strange issue with libnsdfile (1.0.10beta6 and
earlier).
it seems to be related to SFM_RDWR mode again. if i open an existing
(but empty) file in RDWR mode, then switch to UPDATE_HEADER_AUTO mode,
then write to the file, then try to seek to the end of the file in
order to write again: then the seek command will fail or misbehave.
when seeking to file-end, SEEK SET, it will fail with "Internal
psf_fseek() failed.", if seeking to 0, SEEK_END, it will just seek to
zero regardless of the number of frames in the file.
all this proceeds if not switching to UPDATE_HEADER_AUTO. though not
included in the test case, i got the same behavior when using
WRITE_HEADER_NOW after each write instead of UPDATE_HEADER_AUTO with
my "real-world" code.
this behavior seems to be independent from the sndfile format, but
just tested with WAV/16bit, AIFF/16bit, AIFF/float.
attached the "small test case", hope erik will like it again...
bests,
martin
/*
* compile with:
*
* gcc -o seek -Wall -lsndfile seek.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sndfile.h>
int
main (int argc,
char **argv)
{
SF_INFO info;
int mode;
sf_count_t file_frames;
SNDFILE *file;
char *filename = "/tmp/sndtest.aiff";
/* create soundfile */
mode = SFM_WRITE;
info.samplerate = 48000;
info.channels = 2;
/* behavior seems to be bound to a specific file format */
info.format = SF_FORMAT_AIFF | SF_FORMAT_PCM_16;
/* delete if already there */
{
struct stat st;
if (! stat(filename, &st))
{
remove(filename);
}
}
/* open */
if ((file = sf_open(filename, mode, &info)) == NULL)
{
fprintf(stderr, "libsndfile(open): %s\n", sf_strerror(file));
exit(EXIT_FAILURE);
}
/* close without writing: just write header */
if (sf_close(file))
{
fprintf(stderr, "libsndfile(close): %s\n", sf_strerror(file));
exit(EXIT_FAILURE);
}
/* open again for writing */
mode = SFM_RDWR; /* !!! */
info.format = 0;
if ((file = sf_open(filename, mode, &info)) == NULL)
{
fprintf(stderr, "libsndfile(open): %s\n", sf_strerror(file));
exit(EXIT_FAILURE);
}
/* remember number of frames in file */
file_frames = info.frames;
/* in auto header update mode, seeking to the end of the file with
SEEK_SET will fail from the 2nd seek on. seeking to 0, SEEK_END
will seek to 0 anyway */
if (! sf_command(file, SFC_SET_UPDATE_HEADER_AUTO, NULL, SF_TRUE))
{
fprintf(stderr, "libsndfile(sf_command): %s\n", sf_strerror(file));
exit(EXIT_FAILURE);
}
/* now write some frames */
{
float buffer[1024];
int blocks = 4; /* we want to write blocks times the buffer */
long err;
int frames = 1024 / info.channels;
int i;
for (i = 0; i < blocks; ++i)
{
fprintf(stderr, "trying to seek to position %d, file_frames: %ld\n", i * frames, (long)file_frames);
/* this will fail from the 2nd seek on */
if ((err = sf_seek(file, i * frames, SEEK_SET)) == -1)
/* this will seek to 0 regardless of the number of frames in
the file */
/* if ((err = sf_seek(file, 0, SEEK_END)) == -1) */
{
fprintf(stderr, "libsndfile(sf_seek): %s\n", sf_strerror(file));
}
else
{
fprintf(stderr, "seeked to position %ld\n", err);
}
/* write */
if ((err = sf_writef_float(file, buffer, frames)) == -1)
{
fprintf(stderr, "libsndfile: sf_writef_float(): %s\n", sf_strerror(file));
}
else
{
fprintf(stderr, "wrote %ld frames\n", err);
file_frames += err;
}
}
}
/* close */
if (sf_close(file))
{
fprintf(stderr, "libsndfile(close): %s\n", sf_strerror(file));
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
} /* main */