kopia lustrzana https://github.com/xdsopl/robot36
added support for write to alsa devices and wav files
rodzic
5458a53aec
commit
514ddea9f7
90
alsa.c
90
alsa.c
|
@ -16,7 +16,7 @@ typedef struct {
|
|||
void (*info)(pcm_t *);
|
||||
int (*rate)(pcm_t *);
|
||||
int (*channels)(pcm_t *);
|
||||
int (*read)(struct pcm *, short *, int);
|
||||
int (*rw)(struct pcm *, short *, int);
|
||||
snd_pcm_t *pcm;
|
||||
int r;
|
||||
int c;
|
||||
|
@ -58,14 +58,29 @@ int read_alsa(pcm_t *pcm, short *buff, int frames)
|
|||
return 1;
|
||||
}
|
||||
|
||||
int open_alsa(pcm_t **p, char *name)
|
||||
int write_alsa(pcm_t *pcm, short *buff, int frames)
|
||||
{
|
||||
alsa_t *alsa = (alsa_t *)pcm;
|
||||
int got = 0;
|
||||
while (0 < frames) {
|
||||
while ((got = snd_pcm_writei(alsa->pcm, buff, frames)) < 0) {
|
||||
snd_pcm_prepare(alsa->pcm);
|
||||
fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Overrun >>>>>>>>>>>>>>>\n");
|
||||
}
|
||||
buff += got * alsa->c;
|
||||
frames -= got;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int open_alsa_read(pcm_t **p, char *name)
|
||||
{
|
||||
alsa_t *alsa = (alsa_t *)malloc(sizeof(alsa_t));
|
||||
alsa->close = close_alsa;
|
||||
alsa->info = info_alsa;
|
||||
alsa->rate = rate_alsa;
|
||||
alsa->channels = channels_alsa;
|
||||
alsa->read = read_alsa;
|
||||
alsa->rw = read_alsa;
|
||||
|
||||
snd_pcm_t *pcm;
|
||||
snd_pcm_hw_params_t *params;
|
||||
|
@ -132,3 +147,72 @@ int open_alsa(pcm_t **p, char *name)
|
|||
return 1;
|
||||
}
|
||||
|
||||
int open_alsa_write(pcm_t **p, char *name, int rate, int channels)
|
||||
{
|
||||
alsa_t *alsa = (alsa_t *)malloc(sizeof(alsa_t));
|
||||
alsa->close = close_alsa;
|
||||
alsa->info = info_alsa;
|
||||
alsa->rate = rate_alsa;
|
||||
alsa->channels = channels_alsa;
|
||||
alsa->rw = write_alsa;
|
||||
|
||||
snd_pcm_t *pcm;
|
||||
snd_pcm_hw_params_t *params;
|
||||
snd_pcm_hw_params_alloca(¶ms);
|
||||
|
||||
if (snd_pcm_open(&pcm, name, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
|
||||
fprintf(stderr, "Error opening PCM device %s\n", name);
|
||||
free(alsa);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (snd_pcm_hw_params_any(pcm, params) < 0) {
|
||||
fprintf(stderr, "Can not configure this PCM device.\n");
|
||||
snd_pcm_close(alsa->pcm);
|
||||
free(alsa);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (snd_pcm_hw_params_set_access(pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
|
||||
fprintf(stderr, "Error setting access.\n");
|
||||
snd_pcm_close(alsa->pcm);
|
||||
free(alsa);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (snd_pcm_hw_params_set_format(pcm, params, SND_PCM_FORMAT_S16_LE) < 0) {
|
||||
fprintf(stderr, "Error setting S16_LE format.\n");
|
||||
snd_pcm_close(alsa->pcm);
|
||||
free(alsa);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (snd_pcm_hw_params_set_rate_resample(pcm, params, 0) < 0) {
|
||||
fprintf(stderr, "Error disabling resampling.\n");
|
||||
snd_pcm_close(alsa->pcm);
|
||||
free(alsa);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (snd_pcm_hw_params_set_rate_near(pcm, params, (unsigned int *)&rate, 0) < 0) {
|
||||
fprintf(stderr, "Error setting rate.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (snd_pcm_hw_params_set_channels_near(pcm, params, (unsigned int *)&channels) < 0) {
|
||||
fprintf(stderr, "Error setting channels.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (snd_pcm_hw_params(pcm, params) < 0) {
|
||||
fprintf(stderr, "Error setting HW params.\n");
|
||||
snd_pcm_close(alsa->pcm);
|
||||
free(alsa);
|
||||
return 0;
|
||||
}
|
||||
alsa->pcm = pcm;
|
||||
alsa->r = rate;
|
||||
alsa->c = channels;
|
||||
*p = (pcm_t *)alsa;
|
||||
return 1;
|
||||
}
|
||||
|
|
3
alsa.h
3
alsa.h
|
@ -9,6 +9,7 @@ You should have received a copy of the CC0 Public Domain Dedication along with t
|
|||
#ifndef ALSA_H
|
||||
#define ALSA_H
|
||||
#include "pcm.h"
|
||||
int open_alsa(pcm_t **, char *);
|
||||
int open_alsa_read(pcm_t **, char *);
|
||||
int open_alsa_write(pcm_t **, char *, int, int);
|
||||
#endif
|
||||
|
||||
|
|
2
decode.c
2
decode.c
|
@ -46,7 +46,7 @@ int main(int argc, char **argv)
|
|||
if (argc == 3)
|
||||
ppm_name = argv[2];
|
||||
|
||||
if (!open_pcm(&pcm, pcm_name)) {
|
||||
if (!open_pcm_read(&pcm, pcm_name)) {
|
||||
fprintf(stderr, "couldnt open %s\n", pcm_name);
|
||||
return 1;
|
||||
}
|
||||
|
|
22
pcm.c
22
pcm.c
|
@ -36,15 +36,29 @@ int channels_pcm(pcm_t *pcm)
|
|||
|
||||
int read_pcm(pcm_t *pcm, short *buff, int frames)
|
||||
{
|
||||
return pcm->read(pcm, buff, frames);
|
||||
return pcm->rw(pcm, buff, frames);
|
||||
}
|
||||
|
||||
int open_pcm(pcm_t **p, char *name)
|
||||
int write_pcm(pcm_t *pcm, short *buff, int frames)
|
||||
{
|
||||
return pcm->rw(pcm, buff, frames);
|
||||
}
|
||||
|
||||
int open_pcm_read(pcm_t **p, char *name)
|
||||
{
|
||||
if (strstr(name, "plughw:") == name || strstr(name, "hw:") == name || strstr(name, "default") == name)
|
||||
return open_alsa(p, name);
|
||||
return open_alsa_read(p, name);
|
||||
if (strstr(name, ".wav") == (name + (strlen(name) - strlen(".wav"))))
|
||||
return open_wav(p, name);
|
||||
return open_wav_read(p, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int open_pcm_write(pcm_t **p, char *name, int rate, int channels)
|
||||
{
|
||||
if (strstr(name, "plughw:") == name || strstr(name, "hw:") == name || strstr(name, "default") == name)
|
||||
return open_alsa_write(p, name, rate, channels);
|
||||
if (strstr(name, ".wav") == (name + (strlen(name) - strlen(".wav"))))
|
||||
return open_wav_write(p, name, rate, channels);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
6
pcm.h
6
pcm.h
|
@ -14,7 +14,7 @@ typedef struct pcm {
|
|||
void (*info)(struct pcm *);
|
||||
int (*rate)(struct pcm *);
|
||||
int (*channels)(struct pcm *);
|
||||
int (*read)(struct pcm *, short *, int);
|
||||
int (*rw)(struct pcm *, short *, int);
|
||||
} pcm_t;
|
||||
|
||||
void close_pcm(pcm_t *);
|
||||
|
@ -22,7 +22,9 @@ void info_pcm(pcm_t *);
|
|||
int rate_pcm(pcm_t *);
|
||||
int channels_pcm(pcm_t *);
|
||||
int read_pcm(pcm_t *, short *, int);
|
||||
int open_pcm(pcm_t **, char *);
|
||||
int write_pcm(pcm_t *, short *, int);
|
||||
int open_pcm_read(pcm_t **, char *);
|
||||
int open_pcm_write(pcm_t **, char *, int, int);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
103
wav.c
103
wav.c
|
@ -34,14 +34,12 @@ typedef struct {
|
|||
void (*info)(pcm_t *);
|
||||
int (*rate)(pcm_t *);
|
||||
int (*channels)(pcm_t *);
|
||||
int (*read)(struct pcm *, short *, int);
|
||||
int (*rw)(struct pcm *, short *, int);
|
||||
void *p;
|
||||
wav_head_t *head;
|
||||
short *b;
|
||||
size_t size;
|
||||
int r;
|
||||
int c;
|
||||
int samples;
|
||||
int index;
|
||||
unsigned int index;
|
||||
} wav_t;
|
||||
|
||||
void close_wav(pcm_t *pcm)
|
||||
|
@ -53,63 +51,106 @@ void close_wav(pcm_t *pcm)
|
|||
void info_wav(pcm_t *pcm)
|
||||
{
|
||||
wav_t *wav = (wav_t *)pcm;
|
||||
fprintf(stderr, "%d channel(s), %d rate, %d samples\n", wav->c, wav->r, wav->samples);
|
||||
fprintf(stderr, "%d channel(s), %d rate, %d samples\n", wav->head->NumChannels, wav->head->SampleRate, wav->head->Subchunk2Size / 2);
|
||||
}
|
||||
int rate_wav(pcm_t *pcm)
|
||||
{
|
||||
wav_t *wav = (wav_t *)pcm;
|
||||
return wav->r;
|
||||
return wav->head->SampleRate;
|
||||
}
|
||||
int channels_wav(pcm_t *pcm)
|
||||
{
|
||||
wav_t *wav = (wav_t *)pcm;
|
||||
return wav->c;
|
||||
return wav->head->NumChannels;
|
||||
}
|
||||
int read_wav(pcm_t *pcm, short *buff, int frames)
|
||||
{
|
||||
wav_t *wav = (wav_t *)pcm;
|
||||
if ((wav->index + frames * wav->c) > wav->samples)
|
||||
if ((wav->index + frames * wav->head->NumChannels) > (wav->head->Subchunk2Size / 2))
|
||||
return 0;
|
||||
memcpy(buff, wav->b + wav->index, sizeof(short) * frames * wav->c);
|
||||
wav->index += frames * wav->c;
|
||||
memcpy(buff, wav->b + wav->index, sizeof(short) * frames * wav->head->NumChannels);
|
||||
wav->index += frames * wav->head->NumChannels;
|
||||
return 1;
|
||||
}
|
||||
int write_wav(pcm_t *pcm, short *buff, int frames)
|
||||
{
|
||||
wav_t *wav = (wav_t *)pcm;
|
||||
if ((wav->index + frames * wav->head->NumChannels) > (wav->head->Subchunk2Size / 2))
|
||||
return 0;
|
||||
memcpy(wav->b + wav->index, buff, sizeof(short) * frames * wav->head->NumChannels);
|
||||
wav->index += frames * wav->head->NumChannels;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int open_wav(pcm_t **p, char *name)
|
||||
int open_wav_read(pcm_t **p, char *name)
|
||||
{
|
||||
wav_t *wav = (wav_t *)malloc(sizeof(wav_t));
|
||||
wav->close = close_wav;
|
||||
wav->info = info_wav;
|
||||
wav->rate = rate_wav;
|
||||
wav->channels = channels_wav;
|
||||
wav->read = read_wav;
|
||||
wav->rw = read_wav;
|
||||
if (!mmap_file_ro(&wav->p, name, &wav->size)) {
|
||||
fprintf(stderr, "couldnt open wav file %s!\n", name);
|
||||
free(wav);
|
||||
return 0;
|
||||
}
|
||||
wav->head = (wav_head_t *)wav->p;
|
||||
wav->b = (short *)(wav->p + sizeof(wav_head_t));
|
||||
|
||||
if (wav->head->ChunkID != 0x46464952 || wav->head->Format != 0x45564157 ||
|
||||
wav->head->Subchunk1ID != 0x20746d66 || wav->head->Subchunk1Size != 16 ||
|
||||
wav->head->AudioFormat != 1 || wav->head->Subchunk2ID != 0x61746164) {
|
||||
fprintf(stderr, "unsupported WAV file!\n");
|
||||
munmap_file(wav->p, wav->size);
|
||||
free(wav);
|
||||
return 0;
|
||||
}
|
||||
if (wav->head->BitsPerSample != 16) {
|
||||
fprintf(stderr, "only 16bit WAV supported!\n");
|
||||
munmap_file(wav->p, wav->size);
|
||||
free(wav);
|
||||
return 0;
|
||||
}
|
||||
wav->index = 0;
|
||||
*p = (pcm_t *)wav;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int open_wav_write(pcm_t **p, char *name, int rate, int channels)
|
||||
{
|
||||
wav_t *wav = (wav_t *)malloc(sizeof(wav_t));
|
||||
wav->close = close_wav;
|
||||
wav->info = info_wav;
|
||||
wav->rate = rate_wav;
|
||||
wav->channels = channels_wav;
|
||||
wav->rw = write_wav;
|
||||
wav->size = 4096;
|
||||
if (!mmap_file_rw(&wav->p, name, wav->size)) {
|
||||
fprintf(stderr, "couldnt open wav file %s!\n", name);
|
||||
free(wav);
|
||||
return 0;
|
||||
}
|
||||
wav_head_t *head = (wav_head_t *)wav->p;
|
||||
wav->b = (short *)(wav->p + sizeof(wav_head_t));
|
||||
|
||||
if (head->ChunkID != 0x46464952 || head->Format != 0x45564157 ||
|
||||
head->Subchunk1ID != 0x20746d66 || head->Subchunk1Size != 16 ||
|
||||
head->AudioFormat != 1 || head->Subchunk2ID != 0x61746164) {
|
||||
fprintf(stderr, "unsupported WAV file!\n");
|
||||
munmap_file(wav->p, wav->size);
|
||||
free(wav);
|
||||
return 0;
|
||||
}
|
||||
if (head->BitsPerSample != 16) {
|
||||
fprintf(stderr, "only 16bit WAV supported!\n");
|
||||
munmap_file(wav->p, wav->size);
|
||||
free(wav);
|
||||
return 0;
|
||||
}
|
||||
wav->c = head->NumChannels;
|
||||
wav->samples = head->Subchunk2Size / 2;
|
||||
int samples = (wav->size - 44) / 2;
|
||||
wav->index = 0;
|
||||
wav->r = head->SampleRate;
|
||||
|
||||
head->ChunkID = 0x46464952;
|
||||
head->ChunkSize = 36 + 2 * samples;
|
||||
head->Format = 0x45564157;
|
||||
head->Subchunk1ID = 0x20746d66;
|
||||
head->Subchunk1Size = 16;
|
||||
head->AudioFormat = 1;
|
||||
head->NumChannels = channels;
|
||||
head->SampleRate = rate;
|
||||
head->ByteRate = 2 * rate;
|
||||
head->BlockAlign = 2;
|
||||
head->BitsPerSample = 16;
|
||||
head->Subchunk2ID = 0x61746164;
|
||||
head->Subchunk2Size = 2 * samples;
|
||||
|
||||
*p = (pcm_t *)wav;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
3
wav.h
3
wav.h
|
@ -9,5 +9,6 @@ You should have received a copy of the CC0 Public Domain Dedication along with t
|
|||
#ifndef WAV_H
|
||||
#define WAV_H
|
||||
#include "pcm.h"
|
||||
int open_wav(pcm_t **, char *);
|
||||
int open_wav_read(pcm_t **, char *);
|
||||
int open_wav_write(pcm_t **, char *, int, int);
|
||||
#endif
|
||||
|
|
Ładowanie…
Reference in New Issue