wav.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. * This file is part of the libsigrok project.
  3. *
  4. * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include <unistd.h>
  22. #include <fcntl.h>
  23. #include <string.h>
  24. #include "libsigrok.h"
  25. #include "libsigrok-internal.h"
  26. #define LOG_PREFIX "input/wav"
  27. #define CHUNK_SIZE 4096
  28. struct context {
  29. uint64_t samplerate;
  30. int samplesize;
  31. int num_channels;
  32. };
  33. static int get_wav_header(const char *filename, char *buf)
  34. {
  35. struct stat st;
  36. int fd, l;
  37. l = strlen(filename);
  38. if (l <= 4 || strcasecmp(filename + l - 4, ".wav"))
  39. return SR_ERR;
  40. if (stat(filename, &st) == -1)
  41. return SR_ERR;
  42. if (st.st_size <= 45)
  43. /* Minimum size of header + 1 8-bit mono PCM sample. */
  44. return SR_ERR;
  45. if ((fd = open(filename, O_RDONLY)) == -1)
  46. return SR_ERR;
  47. l = read(fd, buf, 40);
  48. close(fd);
  49. if (l != 40)
  50. return SR_ERR;
  51. return SR_OK;
  52. }
  53. static int format_match(const char *filename)
  54. {
  55. char buf[40];
  56. if (get_wav_header(filename, buf) != SR_OK)
  57. return FALSE;
  58. if (strncmp(buf, "RIFF", 4))
  59. return FALSE;
  60. if (strncmp(buf + 8, "WAVE", 4))
  61. return FALSE;
  62. if (strncmp(buf + 12, "fmt ", 4))
  63. return FALSE;
  64. if (GUINT16_FROM_LE(*(uint16_t *)(buf + 20)) != 1)
  65. /* Not PCM. */
  66. return FALSE;
  67. if (strncmp(buf + 36, "data", 4))
  68. return FALSE;
  69. return TRUE;
  70. }
  71. static int init(struct sr_input *in, const char *filename)
  72. {
  73. struct sr_channel *ch;
  74. struct context *ctx;
  75. char buf[40], channelname[8];
  76. int i;
  77. if (get_wav_header(filename, buf) != SR_OK)
  78. return SR_ERR;
  79. if (!(ctx = g_try_malloc0(sizeof(struct context))))
  80. return SR_ERR_MALLOC;
  81. /* Create a virtual device. */
  82. in->sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, NULL, NULL, NULL);
  83. in->sdi->priv = ctx;
  84. ctx->samplerate = GUINT32_FROM_LE(*(uint32_t *)(buf + 24));
  85. ctx->samplesize = GUINT16_FROM_LE(*(uint16_t *)(buf + 34)) / 8;
  86. if (ctx->samplesize != 1 && ctx->samplesize != 2 && ctx->samplesize != 4) {
  87. sr_err("only 8, 16 or 32 bits per sample supported.");
  88. return SR_ERR;
  89. }
  90. if ((ctx->num_channels = GUINT16_FROM_LE(*(uint16_t *)(buf + 22))) > 20) {
  91. sr_err("%d channels seems crazy.", ctx->num_channels);
  92. return SR_ERR;
  93. }
  94. for (i = 0; i < ctx->num_channels; i++) {
  95. snprintf(channelname, 8, "CH%d", i + 1);
  96. if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, channelname)))
  97. return SR_ERR;
  98. in->sdi->channels = g_slist_append(in->sdi->channels, ch);
  99. }
  100. return SR_OK;
  101. }
  102. static int loadfile(struct sr_input *in, const char *filename)
  103. {
  104. struct sr_datafeed_packet packet;
  105. struct sr_datafeed_meta meta;
  106. struct sr_datafeed_analog analog;
  107. struct sr_config *src;
  108. struct context *ctx;
  109. float fdata[CHUNK_SIZE];
  110. uint64_t sample;
  111. int num_samples, chunk_samples, s, c, fd, l;
  112. char buf[CHUNK_SIZE];
  113. ctx = in->sdi->priv;
  114. /* Send header packet to the session bus. */
  115. std_session_send_df_header(in->sdi, LOG_PREFIX);
  116. packet.type = SR_DF_META;
  117. packet.payload = &meta;
  118. src = sr_config_new(SR_CONF_SAMPLERATE,
  119. g_variant_new_uint64(ctx->samplerate));
  120. meta.config = g_slist_append(NULL, src);
  121. sr_session_send(in->sdi, &packet);
  122. sr_config_free(src);
  123. if ((fd = open(filename, O_RDONLY)) == -1)
  124. return SR_ERR;
  125. lseek(fd, 40, SEEK_SET);
  126. l = read(fd, buf, 4);
  127. num_samples = GUINT32_FROM_LE((uint32_t)*(buf));
  128. num_samples /= ctx->samplesize / ctx->num_channels;
  129. while (TRUE) {
  130. if ((l = read(fd, buf, CHUNK_SIZE)) < 1)
  131. break;
  132. chunk_samples = l / ctx->samplesize / ctx->num_channels;
  133. for (s = 0; s < chunk_samples; s++) {
  134. for (c = 0; c < ctx->num_channels; c++) {
  135. sample = 0;
  136. memcpy(&sample, buf + s * ctx->samplesize + c, ctx->samplesize);
  137. switch (ctx->samplesize) {
  138. case 1:
  139. /* 8-bit PCM samples are unsigned. */
  140. fdata[s + c] = (uint8_t)sample / 255.0;
  141. break;
  142. case 2:
  143. fdata[s + c] = GINT16_FROM_LE(sample) / 32767.0;
  144. break;
  145. case 4:
  146. fdata[s + c] = GINT32_FROM_LE(sample) / 65535.0;
  147. break;
  148. }
  149. }
  150. }
  151. packet.type = SR_DF_ANALOG;
  152. packet.payload = &analog;
  153. analog.channels = in->sdi->channels;
  154. analog.num_samples = chunk_samples;
  155. analog.mq = 0;
  156. analog.unit = 0;
  157. analog.data = fdata;
  158. sr_session_send(in->sdi, &packet);
  159. }
  160. close(fd);
  161. packet.type = SR_DF_END;
  162. sr_session_send(in->sdi, &packet);
  163. return SR_OK;
  164. }
  165. SR_PRIV struct sr_input_format input_wav = {
  166. .id = "wav",
  167. .description = "WAV file",
  168. .format_match = format_match,
  169. .init = init,
  170. .loadfile = loadfile,
  171. };