test_simple.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /*
  2. * nanoalsa/test_simple.c
  3. *
  4. * Copyright (C) 2023 bzt (bztsrc@gitlab) MIT license
  5. *
  6. * Permission is hereby granted, free of charge, to any person
  7. * obtaining a copy of this software and associated documentation
  8. * files (the "Software"), to deal in the Software without
  9. * restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies
  11. * of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * @brief Test playing PCM in the foreground
  27. * https://gitlab.com/bztsrc/nanoalsa
  28. */
  29. #define _POSIX_C_SOURCE 199309L /* needed for timespec */
  30. #include <stdio.h>
  31. #define ALSA_IMPLEMENTATION
  32. #include "nanoalsa.h"
  33. /* riff wave header */
  34. typedef struct {
  35. char str_riff[4]; /* "RIFF" */
  36. int wav_size; /* (file size) - 8 */
  37. char str_wave[4]; /* "WAVE" */
  38. /* Format Header */
  39. char str_fmt[4]; /* "fmt " */
  40. int fmt_chunk_size; /* Should be 16 for PCM */
  41. short audio_format; /* Should be 1 for PCM. 3 for IEEE Float */
  42. short channels; /* number of channels */
  43. int sample_rate; /* eg: 8000, 44100, 48000 */
  44. int byte_rate; /* Number of bytes per second. sample_rate * channels * Bytes Per Sample */
  45. short frame_size; /* channels * Bytes Per Sample */
  46. short bit_depth; /* bits per sample, eg: 8, 16, 24 */
  47. /* Data chunk */
  48. char str_data[4]; /* "data" */
  49. int data_bytes; /* (file size) - 44 */
  50. } wav_header_t;
  51. /* helper to read file into memory */
  52. unsigned char* readfileall(char *file, int *size)
  53. {
  54. unsigned char *data = NULL;
  55. FILE *f;
  56. *size = 0;
  57. f = fopen(file, "rb");
  58. if(f){
  59. fseek(f, 0L, SEEK_END);
  60. *size = ftell(f);
  61. fseek(f, 0L, SEEK_SET);
  62. data = (unsigned char*)malloc(*size);
  63. if(!data) { fprintf(stderr, "unable to allocate memory\n"); exit(1); }
  64. fread(data, 1, *size, f);
  65. fclose(f);
  66. }
  67. return data;
  68. }
  69. /* textual error messages. nanoalsa just returns error codes */
  70. const char *alsa_err[] = {
  71. "ALSA_SUCCESS - ok",
  72. "ALSA_ERR_INP - bad function input arguments",
  73. "ALSA_ERR_DEV - no such device",
  74. "ALSA_ERR_HWPAR - ioctl hw parameter not supported",
  75. "ALSA_ERR_SWPAR - ioctl sw parameter not supported",
  76. "ALSA_ERR_MMAP - failed to mmap status or control registers",
  77. "ALSA_ERR_PREP - failed to prepare channel",
  78. "ALSA_ERR_THREAD - failed to create worker thread"
  79. };
  80. /**
  81. * Main procedure, entry point
  82. */
  83. int main(int argc, char **argv)
  84. {
  85. alsa_t ctx;
  86. int ret, len = 0, fmt = SNDRV_PCM_FORMAT_LAST;
  87. unsigned char *data;
  88. wav_header_t *wav;
  89. /*** read in wav file ***/
  90. if(argc < 2) { fprintf(stderr, "./test_simple <wav>\n"); exit(1); }
  91. data = readfileall(argv[1], &len);
  92. if(!data || len < (int)sizeof(wav_header_t)) { fprintf(stderr, "unable to read wav\n"); exit(1); }
  93. wav = (wav_header_t*)data;
  94. switch(wav->audio_format) {
  95. case 1:
  96. switch(wav->bit_depth) {
  97. case 8: fmt = SNDRV_PCM_FORMAT_U8; break;
  98. case 16: fmt = SNDRV_PCM_FORMAT_S16_LE; break;
  99. case 32: fmt = SNDRV_PCM_FORMAT_S32_LE; break;
  100. }
  101. break;
  102. case 3:
  103. switch(wav->bit_depth) {
  104. case 32: fmt = SNDRV_PCM_FORMAT_FLOAT_LE; break;
  105. case 64: fmt = SNDRV_PCM_FORMAT_FLOAT64_LE; break;
  106. }
  107. break;
  108. }
  109. printf("wav file: %s %u bits, %u channels, length %u frames\n",
  110. wav->audio_format == 3 ? "float" : "int", wav->bit_depth, wav->channels,
  111. wav->data_bytes / wav->frame_size);
  112. /*** open the PCM context ***/
  113. if((ret = alsa_open(&ctx, 0, 0, fmt, wav->sample_rate, wav->channels))) {
  114. fprintf(stderr, "unable to open sound card device: %s\n", alsa_err[ret]);
  115. exit(0);
  116. }
  117. /*** play PCM data ***/
  118. alsa_write(&ctx, data + sizeof(wav_header_t), wav->data_bytes / wav->frame_size);
  119. /*** free resources ***/
  120. alsa_close(&ctx);
  121. free(data);
  122. return 0;
  123. }