--- /dev/null
+/**
+ * @file bmpfile.c
+ * @author Shinichiro Nakamura
+ * @brief 小規模組み込みシステム向けBMP I/Oの実装。
+ */
+
+/*
+ * ===============================================================
+ * Tiny BMP I/O Module
+ * Version 0.0.1
+ * ===============================================================
+ * Copyright (c) 2010-2011 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#include "bmpfile.h"
+#include "bmplowio.h"
+
+/**
+ * @brief BMPファイルを読み込む。
+ * @details
+ * この関数はBMPファイルが「どこに格納されているのか?」について全く感知しない。
+ * また、読み込んだピクセルデータを「どこに格納するのか?」についても感知しない。
+ * ユーザは、これら二つの抽象化された操作を提供する関数へのポインタを提供する必要がある。
+ *
+ * 例えば、小規模組み込みシステムにおいて、BMPファイルのイメージがSDカードやフラッシュ上に書かれているかもしれない。
+ * また、読み込んだピクセルをSPI接続されたSRAMに格納したり、そのままディスプレイに表示したい事もあるだろう。
+ * いずれにせよこれらの機能を実現するのは、この関数に渡すそれぞれの関数内部で実装詳細を提供すれば良い。
+ *
+ * @param func_fread ファイル読み込み関数。
+ * @param extobj_func_fread ファイル読み込み関数に渡すパラメータ。
+ * @param func_pixel_write ピクセル書き込み関数。
+ * @param extobj_pixel_write ピクセル書き込み関数に渡すパラメータ。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpfile_read(
+ int (*func_fread)(void *buf, const unsigned int size, void *extobj_func_fread),
+ void *extobj_func_fread,
+ void (*func_pixel_write)(const int x, const int y, const uint8_t r, const uint8_t g, const uint8_t b, void *extobj_pixel_write),
+ void *extobj_pixel_write)
+{
+ bmp_file_t filehead;
+ bmp_info_t infohead;
+ bmp_rgbquad_t rgbquad;
+
+ bmplowio_header_read(func_fread, extobj_func_fread, &filehead, &infohead);
+ if (bmplowio_have_palette(BMP_INFO_GET_BIT_COUNT(&infohead))) {
+ bmplowio_palette_read(func_fread, extobj_func_fread, &rgbquad, (1 << infohead.biBitCount));
+ }
+ bmplowio_image_read(func_fread, extobj_func_fread, &filehead, &infohead, func_pixel_write, extobj_pixel_write);
+
+ return 0;
+}
+
+/**
+ * @brief BMPファイルを書き込む。
+ * @details
+ * この関数はBMPファイルが「どこに格納されているのか?」について全く感知しない。
+ * また、書き込むためのピクセルデータが「どこに格納されているのか?」についても感知しない。
+ * ユーザは、これら二つの抽象化された操作を提供する関数へのポインタを提供する必要がある。
+ *
+ * 例えば、小規模組み込みシステムにおいて、BMPファイルのイメージをSDカードやフラッシュ上に書きたいかもしれない。
+ * また、書き込むピクセルはSPI接続されたSRAMに格納されているか、ディスプレイ上のメモリから直接取得したい事もあるだろう。
+ * いずれにせよこれらの機能を実現するのは、この関数に渡すそれぞれの関数内部で実装詳細を提供すれば良い。
+ *
+ * @param func_fwrite ファイル書き込み関数。
+ * @param extobj_func_fwrite ファイル書き込み関数に渡すパラメータ。
+ * @param func_pixel_read ピクセル読み込み関数。
+ * @param extobj_pixel_read ピクセル読み込み関数に渡すパラメータ。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpfile_write(
+ const int w,
+ const int h,
+ int (*func_fwrite)(const void *buf, const unsigned int size, void *extobj_func_fwrite),
+ void *extobj_func_fwrite,
+ void (*func_pixel_read)(const int x, const int y, uint8_t *r, uint8_t *g, uint8_t *b, void *extobj_pixel_read),
+ void *extobj_pixel_read)
+{
+ bmp_file_t filehead;
+ bmp_info_t infohead;
+ bmp_rgbquad_t rgbquad;
+
+ BMP_FILE_SET_TYPE(&filehead, BMP_FILE_MAGIC_TEXT);
+ BMP_FILE_SET_SIZE(&filehead, bmplowio_calc_framebytesize(24, w, h) + 54);
+ BMP_FILE_SET_RESERVED1(&filehead, 0);
+ BMP_FILE_SET_RESERVED2(&filehead, 0);
+ BMP_FILE_SET_OFFBITS(&filehead, 54);
+
+ BMP_INFO_SET_SIZE(&infohead, 40);
+ BMP_INFO_SET_WIDTH(&infohead, w);
+ BMP_INFO_SET_HEIGHT(&infohead, h);
+ BMP_INFO_SET_PLANES(&infohead, 1);
+ BMP_INFO_SET_BIT_COUNT(&infohead, 24);
+ BMP_INFO_SET_COMPRESSION(&infohead, 0);
+ BMP_INFO_SET_SIZE_IMAGE(&infohead, bmplowio_calc_framebytesize(24, w, h));
+ BMP_INFO_SET_X_PELS_PER_METER(&infohead, 0);
+ BMP_INFO_SET_Y_PELS_PER_METER(&infohead, 0);
+ BMP_INFO_SET_CLR_USED(&infohead, 0);
+ BMP_INFO_SET_CLR_IMPORTANT(&infohead, 0);
+
+ bmplowio_header_write(func_fwrite, extobj_func_fwrite, &filehead, &infohead);
+ if (bmplowio_have_palette(BMP_INFO_GET_BIT_COUNT(&infohead))) {
+ bmplowio_palette_write(func_fwrite, extobj_func_fwrite, &rgbquad, (1 << infohead.biBitCount));
+ }
+ bmplowio_image_write(func_fwrite, extobj_func_fwrite, &filehead, &infohead, func_pixel_read, extobj_pixel_read);
+
+ return 0;
+}
+
--- /dev/null
+/**
+ * @file bmpfile.h
+ * @author Shinichiro Nakamura
+ * @brief 小規模組み込みシステム向けBMP I/Oの実装。
+ */
+
+/*
+ * ===============================================================
+ * Tiny BMP I/O Module
+ * Version 0.0.1
+ * ===============================================================
+ * Copyright (c) 2010-2011 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#ifndef BMPFILE_H
+#define BMPFILE_H
+
+#include "bmpint.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief BMPファイルを読み込む。
+ * @details
+ * この関数はBMPファイルが「どこに格納されているのか?」について全く感知しない。
+ * また、読み込んだピクセルデータを「どこに格納するのか?」についても感知しない。
+ * ユーザは、これら二つの抽象化された操作を提供する関数へのポインタを提供する必要がある。
+ *
+ * 例えば、小規模組み込みシステムにおいて、BMPファイルのイメージがSDカードやフラッシュ上に書かれているかもしれない。
+ * また、読み込んだピクセルをSPI接続されたSRAMに格納したり、そのままディスプレイに表示したい事もあるだろう。
+ * いずれにせよこれらの機能を実現するのは、この関数に渡すそれぞれの関数内部で実装詳細を提供すれば良い。
+ *
+ * @param func_fread ファイル読み込み関数。
+ * @param extobj_func_fread ファイル読み込み関数に渡すパラメータ。
+ * @param func_pixel_write ピクセル書き込み関数。
+ * @param extobj_pixel_write ピクセル書き込み関数に渡すパラメータ。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpfile_read(
+ int (*func_fread)(void *buf, const unsigned int size, void *extobj_func_fread),
+ void *extobj_func_fread,
+ void (*func_pixel_write)(const int x, const int y, const uint8_t r, const uint8_t g, const uint8_t b, void *extobj_pixel_write),
+ void *extobj_pixel_write);
+
+/**
+ * @brief BMPファイルを書き込む。
+ * @details
+ * この関数はBMPファイルが「どこに格納されているのか?」について全く感知しない。
+ * また、書き込むためのピクセルデータが「どこに格納されているのか?」についても感知しない。
+ * ユーザは、これら二つの抽象化された操作を提供する関数へのポインタを提供する必要がある。
+ *
+ * 例えば、小規模組み込みシステムにおいて、BMPファイルのイメージをSDカードやフラッシュ上に書きたいかもしれない。
+ * また、書き込むピクセルはSPI接続されたSRAMに格納されているか、ディスプレイ上のメモリから直接取得したい事もあるだろう。
+ * いずれにせよこれらの機能を実現するのは、この関数に渡すそれぞれの関数内部で実装詳細を提供すれば良い。
+ *
+ * @param func_fwrite ファイル書き込み関数。
+ * @param extobj_func_fwrite ファイル書き込み関数に渡すパラメータ。
+ * @param func_pixel_read ピクセル読み込み関数。
+ * @param extobj_pixel_read ピクセル読み込み関数に渡すパラメータ。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpfile_write(
+ const int w,
+ const int h,
+ int (*func_fwrite)(const void *buf, const unsigned int size, void *extobj_func_fwrite),
+ void *extobj_func_fwrite,
+ void (*func_pixel_read)(const int x, const int y, uint8_t *r, uint8_t *g, uint8_t *b, void *extobj_pixel_read),
+ void *extobj_pixel_read);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null
+/**
+ * @file bmpimg.c
+ * @author Shinichiro Nakamura
+ * @brief 小規模組み込みシステム向けBMP I/Oの実装。
+ */
+
+/*
+ * ===============================================================
+ * Tiny BMP I/O Module
+ * Version 0.0.1
+ * ===============================================================
+ * Copyright (c) 2010-2011 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#include "bmpimg.h"
+#include "bmpfile.h"
+
+static const unsigned char FONT_X = 5; /**< フォントの横方向サイズ。 */
+static const unsigned char FONT_Y = 7; /**< フォントの縦方向サイズ。 */
+static const unsigned char FONT_MIN_CODE = 0x20; /**< フォントテーブルの最小コード番号。 */
+static const unsigned char FONT_MAX_CODE = 0x7F; /**< フォントテーブルの最大コード番号。 */
+static const unsigned char font5x7_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, // (white space)
+ 0x00, 0x00, 0x5F, 0x00, 0x00, // !
+ 0x00, 0x07, 0x00, 0x07, 0x00, // "
+ 0x14, 0x7F, 0x14, 0x7F, 0x14, // #
+ 0x24, 0x2A, 0x7F, 0x2A, 0x12, // $
+ 0x23, 0x13, 0x08, 0x64, 0x62, // %
+ 0x36, 0x49, 0x55, 0x22, 0x50, // &
+ 0x00, 0x05, 0x03, 0x00, 0x00, // '
+ 0x00, 0x1C, 0x22, 0x41, 0x00, // (
+ 0x00, 0x41, 0x22, 0x1C, 0x00, // )
+ 0x08, 0x2A, 0x1C, 0x2A, 0x08, // *
+ 0x08, 0x08, 0x3E, 0x08, 0x08, // +
+ 0x00, 0x50, 0x30, 0x00, 0x00, // ,
+ 0x08, 0x08, 0x08, 0x08, 0x08, // -
+ 0x00, 0x60, 0x60, 0x00, 0x00, // .
+ 0x20, 0x10, 0x08, 0x04, 0x02, // /
+ 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
+ 0x00, 0x42, 0x7F, 0x40, 0x00, // 1
+ 0x42, 0x61, 0x51, 0x49, 0x46, // 2
+ 0x21, 0x41, 0x45, 0x4B, 0x31, // 3
+ 0x18, 0x14, 0x12, 0x7F, 0x10, // 4
+ 0x27, 0x45, 0x45, 0x45, 0x39, // 5
+ 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
+ 0x01, 0x71, 0x09, 0x05, 0x03, // 7
+ 0x36, 0x49, 0x49, 0x49, 0x36, // 8
+ 0x06, 0x49, 0x49, 0x29, 0x1E, // 9
+ 0x00, 0x36, 0x36, 0x00, 0x00, // :
+ 0x00, 0x56, 0x36, 0x00, 0x00, // ;
+ 0x00, 0x08, 0x14, 0x22, 0x41, // <
+ 0x14, 0x14, 0x14, 0x14, 0x14, // =
+ 0x41, 0x22, 0x14, 0x08, 0x00, // >
+ 0x02, 0x01, 0x51, 0x09, 0x06, // ?
+ 0x32, 0x49, 0x79, 0x41, 0x3E, // @
+ 0x7E, 0x11, 0x11, 0x11, 0x7E, // A
+ 0x7F, 0x49, 0x49, 0x49, 0x36, // B
+ 0x3E, 0x41, 0x41, 0x41, 0x22, // C
+ 0x7F, 0x41, 0x41, 0x22, 0x1C, // D
+ 0x7F, 0x49, 0x49, 0x49, 0x41, // E
+ 0x7F, 0x09, 0x09, 0x01, 0x01, // F
+ 0x3E, 0x41, 0x41, 0x51, 0x32, // G
+ 0x7F, 0x08, 0x08, 0x08, 0x7F, // H
+ 0x00, 0x41, 0x7F, 0x41, 0x00, // I
+ 0x20, 0x40, 0x41, 0x3F, 0x01, // J
+ 0x7F, 0x08, 0x14, 0x22, 0x41, // K
+ 0x7F, 0x40, 0x40, 0x40, 0x40, // L
+ 0x7F, 0x02, 0x04, 0x02, 0x7F, // M
+ 0x7F, 0x04, 0x08, 0x10, 0x7F, // N
+ 0x3E, 0x41, 0x41, 0x41, 0x3E, // O
+ 0x7F, 0x09, 0x09, 0x09, 0x06, // P
+ 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
+ 0x7F, 0x09, 0x19, 0x29, 0x46, // R
+ 0x46, 0x49, 0x49, 0x49, 0x31, // S
+ 0x01, 0x01, 0x7F, 0x01, 0x01, // T
+ 0x3F, 0x40, 0x40, 0x40, 0x3F, // U
+ 0x1F, 0x20, 0x40, 0x20, 0x1F, // V
+ 0x7F, 0x20, 0x18, 0x20, 0x7F, // W
+ 0x63, 0x14, 0x08, 0x14, 0x63, // X
+ 0x03, 0x04, 0x78, 0x04, 0x03, // Y
+ 0x61, 0x51, 0x49, 0x45, 0x43, // Z
+ 0x00, 0x00, 0x7F, 0x41, 0x41, // [
+ 0x02, 0x04, 0x08, 0x10, 0x20, // /
+ 0x41, 0x41, 0x7F, 0x00, 0x00, // ]
+ 0x04, 0x02, 0x01, 0x02, 0x04, // ^
+ 0x40, 0x40, 0x40, 0x40, 0x40, // _
+ 0x00, 0x01, 0x02, 0x04, 0x00, // `
+ 0x20, 0x54, 0x54, 0x54, 0x78, // a
+ 0x7F, 0x48, 0x44, 0x44, 0x38, // b
+ 0x38, 0x44, 0x44, 0x44, 0x20, // c
+ 0x38, 0x44, 0x44, 0x48, 0x7F, // d
+ 0x38, 0x54, 0x54, 0x54, 0x18, // e
+ 0x08, 0x7E, 0x09, 0x01, 0x02, // f
+ 0x08, 0x14, 0x54, 0x54, 0x3C, // g
+ 0x7F, 0x08, 0x04, 0x04, 0x78, // h
+ 0x00, 0x44, 0x7D, 0x40, 0x00, // i
+ 0x20, 0x40, 0x44, 0x3D, 0x00, // j
+ 0x00, 0x7F, 0x10, 0x28, 0x44, // k
+ 0x00, 0x41, 0x7F, 0x40, 0x00, // l
+ 0x7C, 0x04, 0x18, 0x04, 0x78, // m
+ 0x7C, 0x08, 0x04, 0x04, 0x78, // n
+ 0x38, 0x44, 0x44, 0x44, 0x38, // o
+ 0x7C, 0x14, 0x14, 0x14, 0x08, // p
+ 0x08, 0x14, 0x14, 0x18, 0x7C, // q
+ 0x7C, 0x08, 0x04, 0x04, 0x08, // r
+ 0x48, 0x54, 0x54, 0x54, 0x20, // s
+ 0x04, 0x3F, 0x44, 0x40, 0x20, // t
+ 0x3C, 0x40, 0x40, 0x20, 0x7C, // u
+ 0x1C, 0x20, 0x40, 0x20, 0x1C, // v
+ 0x3C, 0x40, 0x30, 0x40, 0x3C, // w
+ 0x44, 0x28, 0x10, 0x28, 0x44, // x
+ 0x0C, 0x50, 0x50, 0x50, 0x3C, // y
+ 0x44, 0x64, 0x54, 0x4C, 0x44, // z
+ 0x00, 0x08, 0x36, 0x41, 0x00, // {
+ 0x00, 0x00, 0x7F, 0x00, 0x00, // |
+ 0x00, 0x41, 0x36, 0x08, 0x00, // }
+ 0x08, 0x08, 0x2A, 0x1C, 0x08, // ->
+ 0x08, 0x1C, 0x2A, 0x08, 0x08 // <-
+};
+
+/**
+ * @brief 文字を描画する。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param x 横方向描画開始ピクセル位置。
+ * @param y 縦方向描画開始ピクセル位置。
+ * @param size 1ピクセルのサイズ。
+ * @param c 文字。
+ * @param color 描画色。
+ */
+static void draw_char(bmpimg_t *p, const int x, const int y, const int size, const char c, bmpcol_t *color) {
+ int i, j;
+ if ((FONT_MIN_CODE <= c) && (c <= FONT_MAX_CODE)) {
+ int aofs = (c - FONT_MIN_CODE) * FONT_X;
+ for (i = 0; i < FONT_X; i++) {
+ unsigned char pat = font5x7_data[aofs + i];
+ for (j = 0; j < FONT_Y; j++) {
+ if (pat & (1 << j)) {
+ bmpimg_fill_box(p, x + (i * size), y + (j * size), x + (i * size) + size - 1, y + (j * size) + size - 1, color);
+ }
+ }
+ }
+ } else {
+ for (i = 0; i < FONT_X; i++) {
+ unsigned char pat = (i % 2) ? 0x55 : 0xAA;
+ for (j = 0; j < FONT_Y; j++) {
+ if (pat & (1 << j)) {
+ bmpimg_fill_box(p, x + (i * size), y + (j * size), x + (i * size) + size - 1, y + (j * size) + size - 1, color);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * @brief BMP画像をオープンする。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param w 画像横方向サイズ。
+ * @param h 画像縦方向サイズ。
+ * @param func_pixel_write ピクセル書き込み関数。
+ * @param extobj_pixel_write ピクセル書き込み関数に渡すパラメータ。
+ * @param func_pixel_read ピクセル読み込み関数。
+ * @param extobj_pixel_read ピクセル読み込み関数に渡すパラメータ。
+ */
+void bmpimg_open(
+ bmpimg_t *p,
+ const int w,
+ const int h,
+ void (*func_pixel_write)(const int x, const int y, const uint8_t r, const uint8_t g, const uint8_t b, void *extobj_pixel_write),
+ void *extobj_pixel_write,
+ void (*func_pixel_read)(const int x, const int y, uint8_t *r, uint8_t *g, uint8_t *b, void *extobj_pixel_read),
+ void *extobj_pixel_read)
+{
+ p->w = w;
+ p->h = h;
+ p->func_pixel_write = func_pixel_write;
+ p->extobj_pixel_write = extobj_pixel_write;
+ p->func_pixel_read = func_pixel_read;
+ p->extobj_pixel_read = extobj_pixel_read;
+}
+
+/**
+ * @brief ボックスを描画する。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param x1 始点X座標。
+ * @param y1 始点Y座標。
+ * @param x2 終点X座標。
+ * @param y2 終点Y座標。
+ * @param color 色。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpimg_draw_box(bmpimg_t *p, const int x1, const int y1, const int x2, const int y2, bmpcol_t *color)
+{
+ int x, y;
+ if ((p->w < x1) || (p->w < x2) || (p->h < y1) || (p->h < y2)) {
+ return -1;
+ }
+ for (y = y1; y <= y2; y++) {
+ p->func_pixel_write(x1, y, color->r, color->g, color->b, p->extobj_pixel_write);
+ p->func_pixel_write(x2, y, color->r, color->g, color->b, p->extobj_pixel_write);
+ }
+ for (x = x1; x <= x2; x++) {
+ p->func_pixel_write(x, y1, color->r, color->g, color->b, p->extobj_pixel_write);
+ p->func_pixel_write(x, y2, color->r, color->g, color->b, p->extobj_pixel_write);
+ }
+ return 0;
+}
+
+/**
+ * @brief ボックスを描画する。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param x1 始点X座標。
+ * @param y1 始点Y座標。
+ * @param x2 終点X座標。
+ * @param y2 終点Y座標。
+ * @param color 色。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpimg_fill_box(bmpimg_t *p, const int x1, const int y1, const int x2, const int y2, bmpcol_t *color)
+{
+ int x, y;
+ if ((p->w < x1) || (p->w < x2) || (p->h < y1) || (p->h < y2)) {
+ return -1;
+ }
+ for (y = y1; y <= y2; y++) {
+ for (x = x1; x <= x2; x++) {
+ p->func_pixel_write(x, y, color->r, color->g, color->b, p->extobj_pixel_write);
+ }
+ }
+ return 0;
+}
+
+/**
+ * @brief 文字列を描画する。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param x 横方向描画開始ピクセル位置。
+ * @param y 縦方向描画開始ピクセル位置。
+ * @param size 1ピクセルのサイズ。
+ * @param text 文字列。
+ * @param color 描画色。
+ */
+int bmpimg_draw_string(bmpimg_t *p, const int x, const int y, const int size, const char *text, bmpcol_t *color)
+{
+ char *strp = (char *)text;
+ int cnt = 0;
+ while (*strp) {
+ draw_char(p, x + ((FONT_X * size) * cnt) + (size * cnt), y, size, *strp, color);
+ strp++;
+ cnt++;
+ }
+ return 0;
+}
+
+static void val_swap(int *a, int *b)
+{
+ int c;
+ c = *a;
+ *a = *b;
+ *b = c;
+}
+
+static int val_abs(int a)
+{
+ if (a < 0) {
+ return -a;
+ }
+ return a;
+}
+
+/**
+ * @brief 線を描画する。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param x1 始点X座標。
+ * @param y1 始点Y座標。
+ * @param x2 終点X座標。
+ * @param y2 終点Y座標。
+ * @param color 色。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpimg_draw_line(bmpimg_t *p, const int x1, const int y1, const int x2, const int y2, bmpcol_t *color)
+{
+ int tmp_x1 = x1;
+ int tmp_y1 = y1;
+ int tmp_x2 = x2;
+ int tmp_y2 = y2;
+ int steep = val_abs(tmp_y2 - tmp_y1) > val_abs(tmp_x2 - tmp_x1);
+ if (steep) {
+ val_swap(&tmp_x1, &tmp_y1);
+ val_swap(&tmp_x2, &tmp_y2);
+ }
+ if (tmp_x1 > tmp_x2) {
+ val_swap(&tmp_x1, &tmp_x2);
+ val_swap(&tmp_y1, &tmp_y2);
+ }
+ int deltax = tmp_x2 - tmp_x1;
+ int deltay = val_abs(tmp_y2 - tmp_y1);
+ int error = deltax / 2;
+ int ystep;
+ int y = tmp_y1;
+ if (tmp_y1 < tmp_y2) {
+ ystep = 1;
+ } else {
+ ystep = -1;
+ }
+ int x;
+ for (x = tmp_x1; x <= tmp_x2; x++) {
+ if (steep) {
+ bmpimg_fill_box(p, y, x, y, x, color);
+ } else {
+ bmpimg_fill_box(p, x, y, x, y, color);
+ }
+ error = error - deltay;
+ if (error < 0) {
+ y = y + ystep;
+ error = error + deltax;
+ }
+ }
+ return 0;
+}
+
+/**
+ * @brief 点を描画する。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param x X座標。
+ * @param y Y座標。
+ * @param color 色。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpimg_draw_pixel(bmpimg_t *p, const int x, const int y, bmpcol_t *color)
+{
+ p->func_pixel_write(x, y, color->r, color->g, color->b, p->extobj_pixel_write);
+ return 0;
+}
+
+/**
+ * @brief チェックボックスを描画する。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param x1 始点X座標。
+ * @param y1 始点Y座標。
+ * @param x2 終点X座標。
+ * @param y2 終点Y座標。
+ * @param state 選択状態。
+ * @param color 色。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+void bmpimg_draw_checkbox(
+ bmpimg_t *p,
+ const int x1,
+ const int y1,
+ const int x2,
+ const int y2,
+ const int state,
+ bmpcol_t *color)
+{
+ bmpimg_draw_box(p, x1, y1, x2, y2, color);
+ if (state) {
+ bmpimg_draw_line(p, x1, y1, x2, y2, color);
+ bmpimg_draw_line(p, x1, y2, x2, y1, color);
+ }
+}
+
+/**
+ * @brief プログレスバーを描画する。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param x1 始点X座標。
+ * @param y1 始点Y座標。
+ * @param x2 終点X座標。
+ * @param y2 終点Y座標。
+ * @param min 最小値。
+ * @param max 最大値。
+ * @param value 現在値。
+ * @param color 色。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+void bmpimg_draw_progressbar(
+ bmpimg_t *p,
+ const int x1,
+ const int y1,
+ const int x2,
+ const int y2,
+ const int min,
+ const int max,
+ const int value,
+ bmpcol_t *color)
+{
+ bmpimg_draw_box(p, x1, y1, x2, y2, color);
+ if ((value < min) || (max < value)) {
+ return;
+ }
+ int tmp_max = max - min;
+ int tmp_val = value - min;
+ int pix = ((x2 - x1) * tmp_val) / tmp_max;
+ bmpimg_fill_box(p, x1 + 1, y1 + 1, x1 + pix - 1, y2 - 1, color);
+}
+
+/**
+ * @brief BMPファイルから読み込む。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param filename ファイル名。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpimg_bmp_read(
+ bmpimg_t *p,
+ int (*func_fread)(void *buf, const uint32_t size, void *extobj_func_fread),
+ void *extobj_func_fread)
+{
+ return bmpfile_read(func_fread, extobj_func_fread, p->func_pixel_write, p->extobj_pixel_write);
+}
+
+/**
+ * @brief BMPファイルに書き込む。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param filename ファイル名。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpimg_bmp_write(
+ bmpimg_t *p,
+ int (*func_fwrite)(const void *buf, const uint32_t size, void *extobj_func_fwrite),
+ void *extobj_func_fwrite)
+{
+ return bmpfile_write(p->w, p->h, func_fwrite, extobj_func_fwrite, p->func_pixel_read, p->extobj_pixel_read);
+}
+
+/**
+ * @brief BMP画像をクローズする。
+ *
+ * @param bit ビット深度。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpimg_close(bmpimg_t *p)
+{
+ return 0;
+}
+
--- /dev/null
+/**
+ * @file bmpimg.h
+ * @author Shinichiro Nakamura
+ * @brief 小規模組み込みシステム向けBMP I/Oの実装。
+ */
+
+/*
+ * ===============================================================
+ * Tiny BMP I/O Module
+ * Version 0.0.1
+ * ===============================================================
+ * Copyright (c) 2010-2011 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#ifndef BMPIMG_H
+#define BMPIMG_H
+
+#include "bmpint.h"
+
+/**
+ * @brief BMP画像ハンドラの実装。
+ */
+typedef struct {
+ int w; /**< 画像横方向サイズ。 */
+ int h; /**< 画像縦方向サイズ。 */
+ void (*func_pixel_write)(const int x, const int y, const uint8_t r, const uint8_t g, const uint8_t b, void *extobj_pixel_write);
+ void *extobj_pixel_write;
+ void (*func_pixel_read)(const int x, const int y, uint8_t *r, uint8_t *g, uint8_t *b, void *extobj_pixel_read);
+ void *extobj_pixel_read;
+} bmpimg_t;
+
+#define BMPIMG_GET_W(BMPIMG) ((BMPIMG)->w)
+#define BMPIMG_GET_H(BMPIMG) ((BMPIMG)->h)
+
+/**
+ * @brief 色定義。
+ * @brief 8ビットでフルレンジ。
+ */
+typedef struct {
+ unsigned char r; /**< 赤。 */
+ unsigned char g; /**< 緑。 */
+ unsigned char b; /**< 青。 */
+} bmpcol_t;
+
+#define BMPIMG_FONT_DOT_WIDTH (5) /**< フォントの横方向ドット数。 */
+#define BMPIMG_FONT_DOT_HEIGHT (7) /**< フォンとの縦方向ドット数。 */
+
+/**
+ * @brief 色を設定する。
+ *
+ * @param COL 色定義。
+ * @param R 赤。
+ * @param G 緑。
+ * @param B 青。
+ */
+#define BMPIMG_SET_COLOR(COL, R, G, B) do { (COL).r = (unsigned char)(R); (COL).g = (unsigned char)(G); (COL).b = (unsigned char)(B); } while (0)
+
+/**
+ * @brief 文字列の幅を取得する。
+ *
+ * @param SIZE サイズ。
+ * @param NSTR 文字列の長さ。
+ *
+ * @return 文字列の幅。
+ */
+#define BMPIMG_GET_STRING_WIDTH(SIZE, NSTR) \
+ ((((SIZE) * (BMPIMG_FONT_DOT_WIDTH + 1)) * ((NSTR) - 1)) + ((SIZE) * (BMPIMG_FONT_DOT_WIDTH)))
+
+/**
+ * @brief 文字列の高さを取得する。
+ *
+ * @param SIZE サイズ。
+ *
+ * @return 文字列の高さ。
+ */
+#define BMPIMG_GET_STRING_HEIGHT(SIZE) \
+ ((SIZE) * (BMPIMG_FONT_DOT_HEIGHT))
+
+/**
+ * @brief BMP画像をオープンする。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param w 画像横方向サイズ。
+ * @param h 画像縦方向サイズ。
+ * @param func_pixel_write ピクセル書き込み関数。
+ * @param extobj_pixel_write ピクセル書き込み関数に渡すパラメータ。
+ * @param func_pixel_read ピクセル読み込み関数。
+ * @param extobj_pixel_read ピクセル読み込み関数に渡すパラメータ。
+ */
+void bmpimg_open(
+ bmpimg_t *p,
+ const int w,
+ const int h,
+ void (*func_pixel_write)(const int x, const int y, const uint8_t r, const uint8_t g, const uint8_t b, void *extobj_pixel_write),
+ void *extobj_pixel_write,
+ void (*func_pixel_read)(const int x, const int y, uint8_t *r, uint8_t *g, uint8_t *b, void *extobj_pixel_read),
+ void *extobj_pixel_read);
+
+/**
+ * @brief ボックスを描画する。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param x1 始点X座標。
+ * @param y1 始点Y座標。
+ * @param x2 終点X座標。
+ * @param y2 終点Y座標。
+ * @param color 色。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpimg_draw_box(bmpimg_t *p, const int x1, const int y1, const int x2, const int y2, bmpcol_t *color);
+
+/**
+ * @brief ボックスを描画する。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param x1 始点X座標。
+ * @param y1 始点Y座標。
+ * @param x2 終点X座標。
+ * @param y2 終点Y座標。
+ * @param color 色。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpimg_fill_box(bmpimg_t *p, const int x1, const int y1, const int x2, const int y2, bmpcol_t *color);
+
+/**
+ * @brief 文字列を描画する。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param x 横方向描画開始ピクセル位置。
+ * @param y 縦方向描画開始ピクセル位置。
+ * @param size 1ピクセルのサイズ。
+ * @param text 文字列。
+ * @param color 描画色。
+ */
+int bmpimg_draw_string(bmpimg_t *p, const int x, const int y, const int size, const char *text, bmpcol_t *color);
+
+/**
+ * @brief 線を描画する。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param x1 始点X座標。
+ * @param y1 始点Y座標。
+ * @param x2 終点X座標。
+ * @param y2 終点Y座標。
+ * @param color 色。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpimg_draw_line(bmpimg_t *p, const int x1, const int y1, const int x2, const int y2, bmpcol_t *color);
+
+/**
+ * @brief 点を描画する。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param x X座標。
+ * @param y Y座標。
+ * @param color 色。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpimg_draw_pixel(bmpimg_t *p, const int x, const int y, bmpcol_t *color);
+
+/**
+ * @brief チェックボックスを描画する。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param x1 始点X座標。
+ * @param y1 始点Y座標。
+ * @param x2 終点X座標。
+ * @param y2 終点Y座標。
+ * @param state 選択状態。
+ * @param color 色。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+void bmpimg_draw_checkbox(
+ bmpimg_t *p,
+ const int x1,
+ const int y1,
+ const int x2,
+ const int y2,
+ const int state,
+ bmpcol_t *color);
+
+/**
+ * @brief プログレスバーを描画する。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param x1 始点X座標。
+ * @param y1 始点Y座標。
+ * @param x2 終点X座標。
+ * @param y2 終点Y座標。
+ * @param min 最小値。
+ * @param max 最大値。
+ * @param value 現在値。
+ * @param color 色。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+void bmpimg_draw_progressbar(
+ bmpimg_t *p,
+ const int x1,
+ const int y1,
+ const int x2,
+ const int y2,
+ const int min,
+ const int max,
+ const int value,
+ bmpcol_t *color);
+
+/**
+ * @brief BMPファイルから読み込む。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param filename ファイル名。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpimg_bmp_read(
+ bmpimg_t *p,
+ int (*func_fread)(void *buf, const uint32_t size, void *extobj_func_fread),
+ void *extobj_func_fread);
+
+/**
+ * @brief BMPファイルに書き込む。
+ *
+ * @param p BMP画像ハンドラ。
+ * @param filename ファイル名。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpimg_bmp_write(
+ bmpimg_t *p,
+ int (*func_fwrite)(const void *buf, const uint32_t size, void *extobj_func_fwrite),
+ void *extobj_func_fwrite);
+
+/**
+ * @brief BMP画像をクローズする。
+ *
+ * @param bit ビット深度。
+ *
+ * @retval 0 成功。
+ * @retval !0 失敗。
+ */
+int bmpimg_close(bmpimg_t *p);
+
+#endif
+
--- /dev/null
+/**
+ * @file bmpint.h
+ * @author Shinichiro Nakamura
+ * @brief 小規模組み込みシステム向けBMP I/Oの実装。
+ */
+
+/*
+ * ===============================================================
+ * Tiny BMP I/O Module
+ * Version 0.0.1
+ * ===============================================================
+ * Copyright (c) 2010-2011 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#ifndef BMPINT_H
+#define BMPINT_H
+
+/**
+ * @note
+ * bmpint.hでは、uint8_tやuint16_tやuint32_tなど、stdint.hで提供されている型定義を提供する。
+ * これらの型定義は、比較的新しいCの仕様を用いているため、環境によっては存在しない。
+ * また、小規模組み込みシステムにおいては、libcに依存できない事もある。
+ * よって、このbmpint.hで環境に合わせて定義を追加するようにしてある。
+ */
+
+#include <stdint.h>
+
+#endif
+
--- /dev/null
+/**
+ * @file bmplowio.c
+ * @author Shinichiro Nakamura
+ * @brief 小規模組み込みシステム向けBMP I/Oの実装。
+ */
+
+/*
+ * ===============================================================
+ * Tiny BMP I/O Module
+ * Version 0.0.1
+ * ===============================================================
+ * Copyright (c) 2010-2011 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#include "bmplowio.h"
+
+static int fread_uint32_t(
+ uint32_t *data,
+ int (*func_fread)(void *buf, const uint32_t size, void *extobj_func_fread),
+ void *extobj_func_fread)
+{
+ unsigned char temp[4];
+ if (!func_fread(temp, 4, extobj_func_fread)) {
+ return -1;
+ }
+ *data =
+ ((((uint32_t)temp[0]) << 0) & 0x000000ff) |
+ ((((uint32_t)temp[1]) << 8) & 0x0000ff00) |
+ ((((uint32_t)temp[2]) << 16) & 0x00ff0000) |
+ ((((uint32_t)temp[3]) << 24) & 0xff000000);
+ return 0;
+
+}
+
+static int fread_uint16_t(
+ uint16_t *data,
+ int (*func_fread)(void *buf, const uint32_t size, void *extobj_func_fread),
+ void *extobj_func_fread)
+{
+ unsigned char temp[2];
+ if (!func_fread(temp, 2, extobj_func_fread)) {
+ return -1;
+ }
+ *data =
+ ((((uint16_t)temp[0]) << 0) & 0x00ff) |
+ ((((uint16_t)temp[1]) << 8) & 0xff00);
+ return 0;
+}
+
+static int fwrite_uint32_t(
+ uint32_t data,
+ int (*func_fwrite)(const void *buf, const uint32_t size, void *extobj_func_fwrite),
+ void *extobj_func_fwrite)
+{
+ unsigned char temp[4];
+ temp[0] = ((data) >> 0) & 0x000000ff;
+ temp[1] = ((data) >> 8) & 0x000000ff;
+ temp[2] = ((data) >> 16) & 0x000000ff;
+ temp[3] = ((data) >> 24) & 0x000000ff;
+ if (!func_fwrite(temp, 4, extobj_func_fwrite)) {
+ return -1;
+ }
+ return 0;
+}
+
+static int fwrite_uint16_t(
+ uint16_t data,
+ int (*func_fwrite)(const void *buf, const uint32_t size, void *extobj_func_fwrite),
+ void *extobj_func_fwrite)
+{
+ unsigned char temp[2];
+ temp[0] = ((data) >> 0) & 0x00ff;
+ temp[1] = ((data) >> 8) & 0x00ff;
+ if (!func_fwrite(temp, 2, extobj_func_fwrite)) {
+ return -1;
+ }
+ return 0;
+}
+
+int bmplowio_header_init(bmp_file_t* filehead, bmp_info_t *infohead)
+{
+ BMP_FILE_SET_TYPE(filehead, 0);
+ BMP_FILE_SET_SIZE(filehead, 0);
+ BMP_FILE_SET_RESERVED1(filehead, 0);
+ BMP_FILE_SET_RESERVED2(filehead, 0);
+ BMP_FILE_SET_OFFBITS(filehead, 0);
+
+ BMP_INFO_SET_SIZE(infohead, 0);
+ BMP_INFO_SET_WIDTH(infohead, 0);
+ BMP_INFO_SET_HEIGHT(infohead, 0);
+ BMP_INFO_SET_PLANES(infohead, 0);
+ BMP_INFO_SET_BIT_COUNT(infohead, 0);
+ BMP_INFO_SET_COMPRESSION(infohead, 0);
+ BMP_INFO_SET_SIZE_IMAGE(infohead, 0);
+ BMP_INFO_SET_X_PELS_PER_METER(infohead, 0);
+ BMP_INFO_SET_Y_PELS_PER_METER(infohead, 0);
+ BMP_INFO_SET_CLR_USED(infohead, 0);
+ BMP_INFO_SET_CLR_IMPORTANT(infohead, 0);
+
+ return 0;
+}
+
+int bmplowio_header_write(
+ int (*func_fwrite)(const void *buf, const uint32_t size, void *extobj_func_fwrite),
+ void *extobj_func_fwrite,
+ bmp_file_t *filehead,
+ bmp_info_t *infohead)
+{
+ fwrite_uint16_t(filehead->bfType, func_fwrite, extobj_func_fwrite);
+ fwrite_uint32_t(filehead->bfSize, func_fwrite, extobj_func_fwrite);
+ fwrite_uint16_t(filehead->bfReserved1, func_fwrite, extobj_func_fwrite);
+ fwrite_uint16_t(filehead->bfReserved2, func_fwrite, extobj_func_fwrite);
+ fwrite_uint32_t(filehead->bfOffBits, func_fwrite, extobj_func_fwrite);
+
+ fwrite_uint32_t(infohead->biSize, func_fwrite, extobj_func_fwrite);
+ fwrite_uint32_t(infohead->biWidth, func_fwrite, extobj_func_fwrite);
+ fwrite_uint32_t(infohead->biHeight, func_fwrite, extobj_func_fwrite);
+ fwrite_uint16_t(infohead->biPlanes, func_fwrite, extobj_func_fwrite);
+ fwrite_uint16_t(infohead->biBitCount, func_fwrite, extobj_func_fwrite);
+ fwrite_uint32_t(infohead->biCompression, func_fwrite, extobj_func_fwrite);
+ fwrite_uint32_t(infohead->biSizeImage, func_fwrite, extobj_func_fwrite);
+ fwrite_uint32_t(infohead->biXPelsPerMeter, func_fwrite, extobj_func_fwrite);
+ fwrite_uint32_t(infohead->biYPelsPerMeter, func_fwrite, extobj_func_fwrite);
+ fwrite_uint32_t(infohead->biClrUsed, func_fwrite, extobj_func_fwrite);
+ fwrite_uint32_t(infohead->biClrImportant, func_fwrite, extobj_func_fwrite);
+
+ return 0;
+}
+
+int bmplowio_palette_write(
+ int (*func_fwrite)(const void *buf, const uint32_t size, void *extobj_func_fwrite),
+ void *extobj_func_fwrite,
+ bmp_rgbquad_t *rgbquad,
+ uint32_t n)
+{
+ bmp_rgbquad_t *p = rgbquad;
+ int i;
+ for (i = 0; i < (int)n; i++) {
+ func_fwrite(&(p->red), 1, extobj_func_fwrite);
+ func_fwrite(&(p->green), 1, extobj_func_fwrite);
+ func_fwrite(&(p->blue), 1, extobj_func_fwrite);
+ func_fwrite(&(p->reserved), 1, extobj_func_fwrite);
+ p++;
+ }
+ return 0;
+}
+
+int bmplowio_image_write(
+ int (*func_fwrite)(const void *buf, const uint32_t size, void *extobj_func_fwrite),
+ void *extobj_func_fwrite,
+ bmp_file_t *filehead,
+ bmp_info_t *infohead,
+ void (*func_pixel_read)(const int x, const int y, uint8_t *r, uint8_t *g, uint8_t *b, void *extobj_pixel_read),
+ void *extobj_pixel_read)
+{
+ const int w = infohead->biWidth;
+ const int h = infohead->biHeight;
+ const int pad = (w * infohead->biBitCount + 31) / 32 * 4 - (w * infohead->biBitCount + 7 ) / 8;
+ int x, y;
+ int i;
+ for (y = 0; y < (int)infohead->biHeight; y++) {
+ for (x = 0; x < (int)infohead->biWidth; x++) {
+ if (infohead->biBitCount == 24) {
+ uint8_t a, b, c;
+ func_pixel_read(x, h - y - 1, &c, &b, &a, extobj_pixel_read);
+ func_fwrite(&a, 1, extobj_func_fwrite);
+ func_fwrite(&b, 1, extobj_func_fwrite);
+ func_fwrite(&c, 1, extobj_func_fwrite);
+ } else {
+ /*
+ * @todo 24ビット深度以外は必要になったら対応する。
+ */
+ }
+ }
+ for (i = 0; i < pad; i++) {
+ uint8_t a = 0x00;
+ func_fwrite(&a, 1, extobj_func_fwrite);
+ }
+ }
+ return 0;
+}
+
+int bmplowio_image_read(
+ int (*func_fread)(void *buf, const uint32_t size, void *extobj_func_fread),
+ void *extobj_func_fread,
+ bmp_file_t *filehead,
+ bmp_info_t *infohead,
+ void (*func_pixel_write)(const int x, const int y, const uint8_t r, const uint8_t g, const uint8_t b, void *extobj_pixel_write),
+ void *extobj_pixel_write)
+{
+ const int w = infohead->biWidth;
+ const int h = infohead->biHeight;
+ const int pad = (w * infohead->biBitCount + 31) / 32 * 4 - (w * infohead->biBitCount + 7 ) / 8;
+ int x, y;
+ int i;
+ for (y = 0; y < (int)infohead->biHeight; y++) {
+ for (x = 0; x < (int)infohead->biWidth; x++) {
+ if (infohead->biBitCount == 24) {
+ uint8_t a, b, c;
+ func_fread(&a, 1, extobj_func_fread);
+ func_fread(&b, 1, extobj_func_fread);
+ func_fread(&c, 1, extobj_func_fread);
+ func_pixel_write(x, h - y - 1, c, b, a, extobj_pixel_write);
+ } else {
+ /*
+ * @todo 24ビット深度以外は必要になったら対応する。
+ */
+ }
+ }
+ for (i = 0; i < pad; i++) {
+ uint8_t a;
+ func_fread(&a, 1, extobj_func_fread);
+ }
+ }
+ return 0;
+}
+
+int bmplowio_header_read(
+ int (*func_fread)(void *buf, const uint32_t size, void *extobj_func_fread),
+ void *extobj_func_fread,
+ bmp_file_t *filehead,
+ bmp_info_t *infohead)
+{
+ fread_uint16_t(&filehead->bfType, func_fread, extobj_func_fread);
+ fread_uint32_t(&filehead->bfSize, func_fread, extobj_func_fread);
+ fread_uint16_t(&filehead->bfReserved1, func_fread, extobj_func_fread);
+ fread_uint16_t(&filehead->bfReserved2, func_fread, extobj_func_fread);
+ fread_uint32_t(&filehead->bfOffBits, func_fread, extobj_func_fread);
+
+ fread_uint32_t(&infohead->biSize, func_fread, extobj_func_fread);
+ fread_uint32_t(&infohead->biWidth, func_fread, extobj_func_fread);
+ fread_uint32_t(&infohead->biHeight, func_fread, extobj_func_fread);
+ fread_uint16_t(&infohead->biPlanes, func_fread, extobj_func_fread);
+ fread_uint16_t(&infohead->biBitCount, func_fread, extobj_func_fread);
+ fread_uint32_t(&infohead->biCompression, func_fread, extobj_func_fread);
+ fread_uint32_t(&infohead->biSizeImage, func_fread, extobj_func_fread);
+ fread_uint32_t(&infohead->biXPelsPerMeter, func_fread, extobj_func_fread);
+ fread_uint32_t(&infohead->biYPelsPerMeter, func_fread, extobj_func_fread);
+ fread_uint32_t(&infohead->biClrUsed, func_fread, extobj_func_fread);
+ fread_uint32_t(&infohead->biClrImportant, func_fread, extobj_func_fread);
+
+ return 0;
+}
+
+int bmplowio_palette_read(
+ int (*func_fread)(void *buf, const uint32_t size, void *extobj_func_fread),
+ void *extobj_func_fread,
+ bmp_rgbquad_t *rgbquad,
+ uint32_t n)
+{
+ bmp_rgbquad_t *p = rgbquad;
+ int i;
+ for (i = 0; i < (int)n; i++) {
+ func_fread(&(p->red), 1, extobj_func_fread);
+ func_fread(&(p->green), 1, extobj_func_fread);
+ func_fread(&(p->blue), 1, extobj_func_fread);
+ func_fread(&(p->reserved), 1, extobj_func_fread);
+ p++;
+ }
+ return 0;
+}
+
+int bmplowio_have_palette(const int biBitCount)
+{
+ if ((biBitCount == 8)
+ || (biBitCount == 4)
+ || (biBitCount == 2)
+ || (biBitCount == 1)) {
+ return 1;
+ }
+ return 0;
+}
+
+int bmplowio_calc_framebytesize(
+ const int biBitCount,
+ const int biWidth,
+ const int biHeight)
+{
+ int bmp_frame_bytesize = -1;
+
+ if (biBitCount == 32) {
+ bmp_frame_bytesize = biWidth * 4 * biHeight;
+ }
+
+ if (biBitCount == 24) {
+ bmp_frame_bytesize =
+ ((biWidth * 3 + 3) / 4) * 4 * biHeight;
+ }
+
+ if (biBitCount == 8) {
+ bmp_frame_bytesize =
+ ((biWidth + 3) / 4) * 4 * biHeight;
+ }
+
+ if (biBitCount == 4) {
+ bmp_frame_bytesize =
+ ((biWidth / 2 + 3) / 4) * 4 * biHeight;
+ }
+
+ if (biBitCount == 2) {
+ bmp_frame_bytesize =
+ ((biWidth / 4 + 3) / 4) * 4 * biHeight;
+ }
+
+ if (biBitCount == 1) {
+ bmp_frame_bytesize =
+ ((biWidth / 8 + 3) / 4) * 4 * biHeight;
+ }
+
+ return bmp_frame_bytesize;
+}
+
--- /dev/null
+/**
+ * @file bmplowio.h
+ * @author Shinichiro Nakamura
+ * @brief 小規模組み込みシステム向けBMP I/Oの実装。
+ */
+
+/*
+ * ===============================================================
+ * Tiny BMP I/O Module
+ * Version 0.0.1
+ * ===============================================================
+ * Copyright (c) 2010-2011 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#ifndef BMPLOWIO_H
+#define BMPLOWIO_H
+
+#include "bmpint.h"
+
+/**
+ * @brief ビットマップファイルを示すマジックテキスト。
+ */
+#define BMP_FILE_MAGIC_TEXT (('B' << 0) | ('M' << 8))
+
+#define BMP_FILE_GET_TYPE(P) ((P)->bfType)
+#define BMP_FILE_GET_SIZE(P) ((P)->bfSize)
+#define BMP_FILE_GET_RESERVED1(P) ((P)->bfReserved1)
+#define BMP_FILE_GET_RESERVED2(P) ((P)->bfReserved2)
+#define BMP_FILE_GET_OFFBITS(P) ((P)->bfOffBits)
+
+#define BMP_FILE_SET_TYPE(P, N) do { (P)->bfType = (N); } while (0)
+#define BMP_FILE_SET_SIZE(P, N) do { (P)->bfSize = (N); } while (0)
+#define BMP_FILE_SET_RESERVED1(P, N) do { (P)->bfReserved1 = (N); } while (0)
+#define BMP_FILE_SET_RESERVED2(P, N) do { (P)->bfReserved2 = (N); } while (0)
+#define BMP_FILE_SET_OFFBITS(P, N) do { (P)->bfOffBits = (N); } while (0)
+
+#define BMP_INFO_GET_SIZE(P) ((P)->biSize)
+#define BMP_INFO_GET_WIDTH(P) ((P)->biWidth)
+#define BMP_INFO_GET_HEIGHT(P) ((P)->biHeight)
+#define BMP_INFO_GET_PLANES(P) ((P)->biPlanes)
+#define BMP_INFO_GET_BIT_COUNT(P) ((P)->biBitCount)
+#define BMP_INFO_GET_COMPRESSION(P) ((P)->biCompression)
+#define BMP_INFO_GET_SIZE_IMAGE(P) ((P)->biSizeImage)
+#define BMP_INFO_GET_X_PELS_PER_METER(P) ((P)->biXPelsPerMeter)
+#define BMP_INFO_GET_Y_PELS_PER_METER(P) ((P)->biYPelsPerMeter)
+#define BMP_INFO_GET_CLR_USED(P) ((P)->biClrUsed)
+#define BMP_INFO_GET_CLR_IMPORTANT(P) ((P)->biClrImportant)
+
+#define BMP_INFO_SET_SIZE(P, N) do { (P)->biSize = (N); } while (0)
+#define BMP_INFO_SET_WIDTH(P, N) do { (P)->biWidth = (N); } while (0)
+#define BMP_INFO_SET_HEIGHT(P, N) do { (P)->biHeight = (N); } while (0)
+#define BMP_INFO_SET_PLANES(P, N) do { (P)->biPlanes = (N); } while (0)
+#define BMP_INFO_SET_BIT_COUNT(P, N) do { (P)->biBitCount = (N); } while (0)
+#define BMP_INFO_SET_COMPRESSION(P, N) do { (P)->biCompression = (N); } while (0)
+#define BMP_INFO_SET_SIZE_IMAGE(P, N) do { (P)->biSizeImage = (N); } while (0)
+#define BMP_INFO_SET_X_PELS_PER_METER(P, N) do { (P)->biXPelsPerMeter = (N); } while (0)
+#define BMP_INFO_SET_Y_PELS_PER_METER(P, N) do { (P)->biYPelsPerMeter = (N); } while (0)
+#define BMP_INFO_SET_CLR_USED(P, N) do { (P)->biClrUsed = (N); } while (0)
+#define BMP_INFO_SET_CLR_IMPORTANT(P, N) do { (P)->biClrImportant = (N); } while (0)
+
+#define BMP_FILE_PRINT(P) \
+ fprintf(stderr, "BMP FILE HEADER : (Type=0x%04x, Size=0x%08x, Reserved1=0x%04x, Reserved2=0x%04x, OffBits=0x%08x)\n", \
+ BMP_FILE_GET_TYPE(P), \
+ BMP_FILE_GET_SIZE(P), \
+ BMP_FILE_GET_RESERVED1(P), \
+ BMP_FILE_GET_RESERVED2(P), \
+ BMP_FILE_GET_OFFBITS(P))
+
+#define BMP_INFO_PRINT(P) \
+ fprintf(stderr, "BMP INFO HEADER : (Size=0x%08x, Width=0x%08x, Height=0x%08x, Planes=0x%04x, BitCount=0x%04x, Compression=0x%08x, SizeImage=0x%08x, XPelsPerMeter=0x%08x, YPelsPerMeter=0x%08x, ClrUsed=0x%08x, ClrImportant=0x%08x)\n", \
+ BMP_INFO_GET_SIZE(P), \
+ BMP_INFO_GET_WIDTH(P), \
+ BMP_INFO_GET_HEIGHT(P), \
+ BMP_INFO_GET_PLANES(P), \
+ BMP_INFO_GET_BIT_COUNT(P), \
+ BMP_INFO_GET_COMPRESSION(P), \
+ BMP_INFO_GET_SIZE_IMAGE(P), \
+ BMP_INFO_GET_X_PELS_PER_METER(P), \
+ BMP_INFO_GET_Y_PELS_PER_METER(P), \
+ BMP_INFO_GET_CLR_USED(P), \
+ BMP_INFO_GET_CLR_IMPORTANT(P))
+
+typedef struct bmp_file {
+ uint16_t bfType;
+ uint32_t bfSize;
+ uint16_t bfReserved1;
+ uint16_t bfReserved2;
+ uint32_t bfOffBits;
+} bmp_file_t;
+
+typedef struct bmp_info {
+ uint32_t biSize;
+ uint32_t biWidth;
+ uint32_t biHeight;
+ uint16_t biPlanes;
+ uint16_t biBitCount;
+ uint32_t biCompression;
+ uint32_t biSizeImage;
+ uint32_t biXPelsPerMeter;
+ uint32_t biYPelsPerMeter;
+ uint32_t biClrUsed;
+ uint32_t biClrImportant;
+} bmp_info_t;
+
+typedef struct bmp_rgbquad {
+ uint8_t blue;
+ uint8_t green;
+ uint8_t red;
+ uint8_t reserved;
+} bmp_rgbquad_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int bmplowio_header_init(
+ bmp_file_t* filehead,
+ bmp_info_t *infohead);
+
+int bmplowio_header_write(
+ int (*func_fwrite)(const void *buf, const uint32_t size, void *extobj_func_fwrite),
+ void *extobj_func_fwrite,
+ bmp_file_t* filehead,
+ bmp_info_t *infohead);
+
+int bmplowio_palette_write(
+ int (*func_fwrite)(const void *buf, const uint32_t size, void *extobj_func_fwrite),
+ void *extobj_func_fwrite,
+ bmp_rgbquad_t *rgbquad,
+ uint32_t n);
+
+int bmplowio_image_write(
+ int (*func_fwrite)(const void *buf, const uint32_t size, void *extobj_func_fwrite),
+ void *extobj_func_fwrite,
+ bmp_file_t *filehead,
+ bmp_info_t *infohead,
+ void (*func_pixel_read)(const int x, const int y, uint8_t *r, uint8_t *g, uint8_t *b, void *extobj_pixel_read),
+ void *extobj_pixel_read);
+
+int bmplowio_image_read(
+ int (*func_fread)(void *buf, const uint32_t size, void *extobj_func_fread),
+ void *extobj_func_fread,
+ bmp_file_t *filehead,
+ bmp_info_t *infohead,
+ void (*func_pixel_write)(const int x, const int y, const uint8_t r, const uint8_t g, const uint8_t b, void *extobj_pixel_write),
+ void *extobj_pixel_write);
+
+int bmplowio_header_read(
+ int (*func_fread)(void *buf, const uint32_t size, void *extobj_func_fread),
+ void *extobj_func_fread,
+ bmp_file_t *filehead,
+ bmp_info_t *infohead);
+
+int bmplowio_palette_read(
+ int (*func_fread)(void *buf, const uint32_t size, void *extobj_func_fread),
+ void *extobj_func_fread,
+ bmp_rgbquad_t *rgbquad,
+ uint32_t n);
+
+int bmplowio_have_palette(const int biBitCount);
+
+int bmplowio_calc_framebytesize(
+ const int biBitCount,
+ const int biWidth,
+ const int biHeight);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null
+/**
+ * @file wavfile.cpp
+ * @author Shinichiro Nakamura
+ * @brief libcベースのWAVファイルモジュール。
+ */
+
+/*
+ * ===============================================================
+ * Tiny WAV I/O Module
+ * Version 0.0.1
+ * ===============================================================
+ * Copyright (c) 2011-2012 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "wavfile.h"
+
+#define DEBUG printf
+
+#define CHUNK_ID_RIFF (('R' << 24) | ('I' << 16) | ('F' << 8) | ('F' << 0))
+#define CHUNK_ID_FMT (('f' << 24) | ('m' << 16) | ('t' << 8) | (' ' << 0))
+#define CHUNK_ID_DATA (('d' << 24) | ('a' << 16) | ('t' << 8) | ('a' << 0))
+
+#define RIFF_CHUNK_FORMAT_WAVE (('W' << 24) | ('A' << 16) | ('V' << 8) | ('E' << 0))
+
+#define BITS_PER_SAMPLE_8 (8)
+#define BITS_PER_SAMPLE_16 (16)
+#define BITS_PER_SAMPLE_24 (24)
+
+#define CHUNK_SIZE_FMT_PCM (16)
+#define CHUNK_SIZE_FMT_EXTENSIBLE (40)
+
+#define CHANNEL_MASK_SPEAKER_FRONT_LEFT (0x00000001)
+#define CHANNEL_MASK_SPEAKER_FRONT_RIGHT (0x00000002)
+#define CHANNEL_MASK_SPEAKER_FRONT_CENTER (0x00000004)
+#define CHANNEL_MASK_SPEAKER_LOW_FREQUENCY (0x00000008)
+#define CHANNEL_MASK_SPEAKER_BACK_LEFT (0x00000010)
+#define CHANNEL_MASK_SPEAKER_BACK_RIGHT (0x00000020)
+#define CHANNEL_MASK_SPEAKER_FRONT_LEFT_OF_CENTER (0x00000040)
+#define CHANNEL_MASK_SPEAKER_FRONT_RIGHT_OF_CENTER (0x00000080)
+#define CHANNEL_MASK_SPEAKER_BACK_CENTER (0x00000100)
+#define CHANNEL_MASK_SPEAKER_SIDE_LEFT (0x00000200)
+#define CHANNEL_MASK_SPEAKER_SIDE_RIGHT (0x00000400)
+#define CHANNEL_MASK_SPEAKER_TOP_CENTER (0x00000800)
+#define CHANNEL_MASK_SPEAKER_TOP_FRONT_LEFT (0x00001000)
+#define CHANNEL_MASK_SPEAKER_TOP_FRONT_CENTER (0x00002000)
+#define CHANNEL_MASK_SPEAKER_TOP_FRONT_RIGHT (0x00004000)
+#define CHANNEL_MASK_SPEAKER_TOP_BACK_LEFT (0x00008000)
+#define CHANNEL_MASK_SPEAKER_TOP_BACK_CENTER (0x00010000)
+#define CHANNEL_MASK_SPEAKER_TOP_BACK_RIGHT (0x00020000)
+#define CHANNEL_MASK_SPEAKER_RESERVED (0x80000000)
+
+struct WAVFILE {
+ FILE *fp; /**< ファイルハンドラ。 */
+ char filename[BUFSIZ]; /**< ファイル名。 */
+ WavFileMode mode; /**< ファイルモード。 */
+ bool info_checked; /**< infoを確認したら真になるフラグ。 */
+ bool data_checked; /**< dataを確認したら真になるフラグ。 */
+ uint32_t data_byte_count; /**< データバイトカウント。 */
+ wavfile_info_t info; /**< 対象ファイルのinfo情報。制御の確認用に用いる。 */
+};
+
+static int WRITE_U32_BE(FILE *fp, const uint32_t value)
+{
+ for (int i = 0; i < 4; i++) {
+ if (fputc((value >> (8 * (3 - i))), fp) == EOF) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int WRITE_U32_LE(FILE *fp, const uint32_t value)
+{
+ for (int i = 0; i < 4; i++) {
+ if (fputc((value >> (8 * i)), fp) == EOF) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int WRITE_U16_LE(FILE *fp, const uint16_t value)
+{
+ for (int i = 0; i < 2; i++) {
+ if (fputc((value >> (8 * i)), fp) == EOF) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int READ_U32_BE(FILE *fp, uint32_t *value)
+{
+ int raw[4];
+ for (int i = 0; i < (int)(sizeof(raw) / sizeof(raw[0])); i++) {
+ raw[i] = fgetc(fp);
+ if (raw[i] == EOF) {
+ *value = 0x00000000;
+ return -1;
+ }
+ }
+ *value =
+ ((uint32_t)raw[0] << 24) |
+ ((uint32_t)raw[1] << 16) |
+ ((uint32_t)raw[2] << 8) |
+ ((uint32_t)raw[3] << 0);
+ return 0;
+}
+
+static int READ_U32_LE(FILE *fp, uint32_t *value)
+{
+ int raw[4];
+ for (int i = 0; i < (int)(sizeof(raw) / sizeof(raw[0])); i++) {
+ raw[i] = fgetc(fp);
+ if (raw[i] == EOF) {
+ *value = 0x00000000;
+ return -1;
+ }
+ }
+ *value =
+ ((uint32_t)raw[3] << 24) |
+ ((uint32_t)raw[2] << 16) |
+ ((uint32_t)raw[1] << 8) |
+ ((uint32_t)raw[0] << 0);
+ return 0;
+}
+
+static int READ_U16_LE(FILE *fp, uint16_t *value)
+{
+ int raw[2];
+ for (int i = 0; i < (int)(sizeof(raw) / sizeof(raw[0])); i++) {
+ raw[i] = fgetc(fp);
+ if (raw[i] == EOF) {
+ *value = 0x00000000;
+ return -1;
+ }
+ }
+ *value =
+ ((uint16_t)raw[1] << 8) |
+ ((uint16_t)raw[0] << 0);
+ return 0;
+}
+
+static WavFileResult chunk_reader_unknown(
+ const uint32_t chunk_id,
+ const uint32_t chunk_size,
+ FILE *fp)
+{
+ for (int i = 0; i < (int)chunk_size; i++) {
+ int c = fgetc(fp);
+ if (c == EOF) {
+ return WavFileResultErrorBrokenChunkData;
+ }
+ }
+ return WavFileResultOK;
+}
+
+static WavFileResult chunk_reader_riff(
+ const uint32_t chunk_id,
+ const uint32_t chunk_size,
+ FILE *fp,
+ uint32_t *format_id)
+{
+ if (READ_U32_BE(fp, format_id) != 0) {
+ return WavFileResultErrorBrokenFormatId;
+ }
+ return WavFileResultOK;
+}
+
+static WavFileResult chunk_reader_fmt(
+ const uint32_t chunk_id,
+ const uint32_t chunk_size,
+ FILE *fp,
+ uint16_t *audio_format,
+ uint16_t *num_channels,
+ uint32_t *sample_rate,
+ uint32_t *byte_rate,
+ uint16_t *block_align,
+ uint16_t *bits_per_sample)
+{
+ uint32_t read_byte_count = 0;
+
+ /*
+ * 2
+ */
+ if (read_byte_count < chunk_size) {
+ if (READ_U16_LE(fp, audio_format) != 0) {
+ return WavFileResultErrorBrokenAudioFormat;
+ }
+ }
+ read_byte_count+=2;
+
+ /*
+ * 2 + 2
+ */
+ if (read_byte_count < chunk_size) {
+ if (READ_U16_LE(fp, num_channels) != 0) {
+ return WavFileResultErrorBrokenNumChannels;
+ }
+ }
+ read_byte_count+=2;
+
+ /*
+ * 2 + 2 + 4
+ */
+ if (read_byte_count < chunk_size) {
+ if (READ_U32_LE(fp, sample_rate) != 0) {
+ return WavFileResultErrorBrokenSampleRate;
+ }
+ }
+ read_byte_count+=4;
+
+ /*
+ * 2 + 2 + 4 + 4
+ */
+ if (read_byte_count < chunk_size) {
+ if (READ_U32_LE(fp, byte_rate) != 0) {
+ return WavFileResultErrorBrokenByteRate;
+ }
+ }
+ read_byte_count+=4;
+
+ /*
+ * 2 + 2 + 4 + 4 + 2
+ */
+ if (read_byte_count < chunk_size) {
+ if (READ_U16_LE(fp, block_align) != 0) {
+ return WavFileResultErrorBrokenBlockAlign;
+ }
+ }
+ read_byte_count+=2;
+
+ /*
+ * 2 + 2 + 4 + 4 + 2 + 2
+ */
+ if (read_byte_count < chunk_size) {
+ if (READ_U16_LE(fp, bits_per_sample) != 0) {
+ return WavFileResultErrorBrokenBitsPerSample;
+ }
+ }
+ read_byte_count+=2;
+
+ /*
+ * 2 + 2 + 4 + 4 + 2 + 2
+ */
+ while (read_byte_count < chunk_size) {
+ if (fgetc(fp) == EOF) {
+ return WavFileResultErrorBrokenChunkData;
+ }
+ read_byte_count++;
+ }
+
+ return WavFileResultOK;
+}
+
+WAVFILE *wavfile_open(const char *filename, WavFileMode mode, WavFileResult *result)
+{
+ /*
+ * ファイル名を検証する。
+ */
+ if (filename == NULL) {
+ *result = WavFileResultErrorInvalidFileName;
+ return NULL;
+ }
+
+ /*
+ * ファイルを開く。
+ */
+ FILE *fp = NULL;
+ switch (mode) {
+ case WavFileModeRead:
+ fp = fopen(filename, "rb");
+ break;
+ case WavFileModeWrite:
+ fp = fopen(filename, "wb");
+ break;
+ default:
+ fp = NULL;
+ break;
+ }
+ if (fp == NULL) {
+ *result = WavFileResultErrorFileOpen;
+ return NULL;
+ }
+
+ /*
+ * ハンドラ領域を確保する。
+ */
+ WAVFILE *p = (WAVFILE *)malloc(sizeof(WAVFILE));
+ if (p == NULL) {
+ *result = WavFileResultErrorMemoryAllocation;
+ return NULL;
+ }
+
+ /*
+ * ハンドラ内部フィールドを設定する。
+ */
+ p->fp = fp;
+ strcpy(p->filename, filename);
+ p->mode = mode;
+ p->info_checked = false;
+ p->data_checked = false;
+ p->data_byte_count = 0;
+ WAVFILE_INFO_AUDIO_FORMAT(&(p->info)) = 0;
+ WAVFILE_INFO_NUM_CHANNELS(&(p->info)) = 0;
+ WAVFILE_INFO_SAMPLE_RATE(&(p->info)) = 0;
+ WAVFILE_INFO_BYTE_RATE(&(p->info)) = 0;
+ WAVFILE_INFO_BLOCK_ALIGN(&(p->info)) = 0;
+ WAVFILE_INFO_BITS_PER_SAMPLE(&(p->info)) = 0;
+
+ *result = WavFileResultOK;
+ return p;
+}
+
+WavFileResult wavfile_read_info(WAVFILE *p, wavfile_info_t *info)
+{
+ WavFileResult result = WavFileResultOK;
+
+ if (p == NULL) {
+ result = WavFileResultErrorInvalidHandler;
+ goto finalize;
+ }
+
+ if (p->info_checked) {
+ result = WavFileResultErrorAlreadyInfoChecked;
+ goto finalize;
+ }
+ if (p->data_checked) {
+ result = WavFileResultErrorAlreadyDataChecked;
+ goto finalize;
+ }
+ if (p->mode != WavFileModeRead) {
+ result = WavFileResultErrorInvalidMode;
+ goto finalize;
+ }
+
+ while (1) {
+ uint32_t chunk_id;
+ uint32_t chunk_size;
+
+ /*
+ * チャンクIDを取得する。
+ */
+ if (READ_U32_BE(p->fp, &chunk_id) != 0) {
+ if (feof(p->fp)) {
+ /*
+ * このループはデータチャンクのデータ先頭に到達して離脱する仕掛け。
+ * チャンクIDを確認するところでEOFになるのは所望のデータに到達できなかった証拠である。
+ */
+ result = WavFileResultErrorNoDataChunk;
+ goto finalize;
+ } else {
+ result = WavFileResultErrorBrokenChunkId;
+ goto finalize;
+ }
+ }
+
+ /*
+ * チャンクサイズを取得する。
+ */
+ if (READ_U32_LE(p->fp, &chunk_size) != 0) {
+ result = WavFileResultErrorBrokenChunkSize;
+ goto finalize;
+ }
+
+#if WAVFILE_DEBUG_ENABLED
+ /*
+ * チャンクIDとチャンクサイズのデバッグ用出力。
+ */
+ DEBUG("chunk_id(0x%04X-%c%c%c%c), chunk_size(%d bytes)\n",
+ chunk_id,
+ (chunk_id >> (8 * 3)),
+ (chunk_id >> (8 * 2)),
+ (chunk_id >> (8 * 1)),
+ (chunk_id >> (8 * 0)),
+ chunk_size);
+#endif
+
+ /*
+ * チャンクIDに従って読み込みを実行する。
+ */
+ switch (chunk_id) {
+ case CHUNK_ID_RIFF:
+ {
+ uint32_t format_id;
+ result = chunk_reader_riff(
+ chunk_id,
+ chunk_size,
+ p->fp,
+ &format_id);
+
+#if WAVFILE_DEBUG_ENABLED
+ /*
+ * フォーマットIDのデバッグ用出力。
+ */
+ DEBUG("\tformat_id(%d)\n", format_id);
+#endif
+
+ if (format_id != RIFF_CHUNK_FORMAT_WAVE) {
+ return WavFileResultErrorInvalidFormatId;
+ }
+ if (result != WavFileResultOK) {
+ goto finalize;
+ }
+ }
+ break;
+ case CHUNK_ID_FMT:
+ {
+ result = chunk_reader_fmt(
+ chunk_id,
+ chunk_size,
+ p->fp,
+ &(p->info.audio_format),
+ &(p->info.num_channels),
+ &(p->info.sample_rate),
+ &(p->info.byte_rate),
+ &(p->info.block_align),
+ &(p->info.bits_per_sample));
+
+ info->audio_format = p->info.audio_format;
+ info->num_channels = p->info.num_channels;
+ info->sample_rate = p->info.sample_rate;
+ info->byte_rate = p->info.byte_rate;
+ info->block_align = p->info.block_align;
+ info->bits_per_sample = p->info.bits_per_sample;
+
+#if WAVFILE_DEBUG_ENABLED
+ /*
+ * フォーマット情報のデバッグ用出力。
+ */
+ DEBUG("\taudio_format(%d)\n", p->info.audio_format);
+ DEBUG("\tnum_channels(%d)\n", p->info.num_channels);
+ DEBUG("\tsample_rate(%d)\n", p->info.sample_rate);
+ DEBUG("\tbyte_rate(%d)\n", p->info.byte_rate);
+ DEBUG("\tblock_align(%d)\n", p->info.block_align);
+ DEBUG("\tbits_per_sample(%d)\n", p->info.bits_per_sample);
+#endif
+
+ if ((p->info.audio_format != WAVFILE_AUDIO_FORMAT_PCM) && (info->audio_format != WAVFILE_AUDIO_FORMAT_EXTENSIBLE)) {
+ return WavFileResultErrorInvalidAudioFormat;
+ }
+ if (result != WavFileResultOK) {
+ goto finalize;
+ }
+ }
+ break;
+ case CHUNK_ID_DATA:
+ {
+ p->info_checked = true;
+ p->data_byte_count = chunk_size;
+ goto finalize;
+ }
+ break;
+ default:
+ {
+ result = chunk_reader_unknown(chunk_id, chunk_size, p->fp);
+ if (result != WavFileResultOK) {
+ goto finalize;
+ }
+ }
+ break;
+ }
+ }
+
+finalize:
+ return result;
+}
+
+/**
+ * @details 音声データは、どんな形式でも常に0.0から1.0の範囲で正規化して出力される。
+ */
+WavFileResult wavfile_read_data(WAVFILE *p, wavfile_data_t *data)
+{
+ if (p == NULL) {
+ return WavFileResultErrorInvalidHandler;
+ }
+
+ if (!p->info_checked) {
+ return WavFileResultErrorNeedInfoChecked;
+ }
+
+ if (p->mode != WavFileModeRead) {
+ return WavFileResultErrorInvalidMode;
+ }
+
+ if (p->data_byte_count == 0) {
+ data->num_channels = 0;
+ for (int i = 0; i < p->info.num_channels; i++) {
+ data->channel_data[i] = 0.5;
+ }
+ return WavFileResultOK;
+ }
+
+ data->num_channels = p->info.num_channels;
+ for (int i = 0; i < p->info.num_channels; i++) {
+ switch (p->info.bits_per_sample) {
+ case BITS_PER_SAMPLE_8:
+ {
+ int c = fgetc(p->fp);
+ if (c == EOF) {
+ return WavFileResultErrorBrokenChunkData;
+ }
+ data->channel_data[i] = (double)c / 0xFF;
+ }
+ p->data_byte_count-=1;
+ break;
+ case BITS_PER_SAMPLE_16:
+ {
+ int c1 = fgetc(p->fp);
+ if (c1 == EOF) {
+ return WavFileResultErrorBrokenChunkData;
+ }
+ int c2 = fgetc(p->fp);
+ if (c2 == EOF) {
+ return WavFileResultErrorBrokenChunkData;
+ }
+ uint16_t n = (((uint16_t)c2 << 8) | ((uint16_t)c1 << 0)) ^ (1 << 15);
+ data->channel_data[i] = (double)n / 0xFFFF;
+ }
+ p->data_byte_count-=2;
+ break;
+ case BITS_PER_SAMPLE_24:
+ {
+ int c1 = fgetc(p->fp);
+ if (c1 == EOF) {
+ return WavFileResultErrorBrokenChunkData;
+ }
+ int c2 = fgetc(p->fp);
+ if (c2 == EOF) {
+ return WavFileResultErrorBrokenChunkData;
+ }
+ int c3 = fgetc(p->fp);
+ if (c3 == EOF) {
+ return WavFileResultErrorBrokenChunkData;
+ }
+ uint32_t n = (((uint32_t)c3 << 16) | ((uint32_t)c2 << 8) | ((uint32_t)c1 << 0)) ^ (1 << 23);
+ data->channel_data[i] = (double)n / 0xFFFFFF;
+ }
+ p->data_byte_count-=3;
+ break;
+ default:
+ return WavFileResultErrorUnsupportedBitsPerSample;
+ }
+ }
+ return WavFileResultOK;
+}
+
+WavFileResult wavfile_write_info(WAVFILE *p, const wavfile_info_t *info)
+{
+ WavFileResult result = WavFileResultOK;
+
+ if (p == NULL) {
+ result = WavFileResultErrorInvalidHandler;
+ goto finalize;
+ }
+
+ if (p->info_checked) {
+ result = WavFileResultErrorAlreadyInfoChecked;
+ goto finalize;
+ }
+
+ if (p->mode != WavFileModeWrite) {
+ result = WavFileResultErrorInvalidMode;
+ goto finalize;
+ }
+
+ p->info.audio_format = info->audio_format;
+ p->info.num_channels = info->num_channels;
+ p->info.sample_rate = info->sample_rate;
+ p->info.byte_rate = info->byte_rate;
+ p->info.block_align = info->block_align;
+ p->info.bits_per_sample = info->bits_per_sample;
+
+ /*
+ *
+ */
+
+ if ((info->audio_format != WAVFILE_AUDIO_FORMAT_PCM) && (info->audio_format != WAVFILE_AUDIO_FORMAT_EXTENSIBLE)) {
+ result = WavFileResultErrorInvalidAudioFormat;
+ goto finalize;
+ }
+
+ if ((info->bits_per_sample != BITS_PER_SAMPLE_8)
+ && (info->bits_per_sample != BITS_PER_SAMPLE_16)
+ && (info->bits_per_sample != BITS_PER_SAMPLE_24)) {
+ result = WavFileResultErrorUnsupportedBitsPerSample;
+ goto finalize;
+ }
+
+ if ((info->num_channels * info->sample_rate * (info->bits_per_sample / 8)) != info->byte_rate) {
+ result = WavFileResultErrorInvalidByteRate;
+ goto finalize;
+ }
+
+ /*
+ * [RIFF]
+ * ------------------------------------------
+ * Big endian 4 bytes : Chunk ID
+ * Little endian 4 bytes : Chunk size
+ * Big endian 4 bytes : Format
+ * ------------------------------------------
+ */
+ if (WRITE_U32_BE(p->fp, CHUNK_ID_RIFF) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U32_LE(p->fp, 0x00000000) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U32_BE(p->fp, RIFF_CHUNK_FORMAT_WAVE) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+
+ /*
+ * [fmt]
+ * ------------------------------------------
+ * Big endian 4 bytes : Sub chunk ID
+ * Little endian 4 bytes : Sub chunk size
+ * Little endian 2 bytes : Audio format
+ * Little endian 2 bytes : Number of channels
+ * Little endian 4 bytes : Sample rate
+ * Little endian 4 bytes : Byte rate
+ * Little endian 2 bytes : Block align
+ * Little endian 2 bytes : Bits per sample
+ * . .
+ * . Additional bytes here (extensible) .
+ * . .
+ * ------------------------------------------
+ */
+ switch (info->audio_format) {
+ case WAVFILE_AUDIO_FORMAT_PCM:
+ {
+ if (WRITE_U32_BE(p->fp, CHUNK_ID_FMT) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U32_LE(p->fp, CHUNK_SIZE_FMT_PCM) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U16_LE(p->fp, info->audio_format) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U16_LE(p->fp, info->num_channels) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U32_LE(p->fp, info->sample_rate) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U32_LE(p->fp, info->byte_rate) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U16_LE(p->fp, info->block_align) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U16_LE(p->fp, info->bits_per_sample) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ }
+ break;
+ case WAVFILE_AUDIO_FORMAT_EXTENSIBLE:
+ {
+ if (WRITE_U32_BE(p->fp, CHUNK_ID_FMT) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U32_LE(p->fp, CHUNK_SIZE_FMT_EXTENSIBLE) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U16_LE(p->fp, info->audio_format) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U16_LE(p->fp, info->num_channels) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U32_LE(p->fp, info->sample_rate) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U32_LE(p->fp, info->byte_rate) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U16_LE(p->fp, info->block_align) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U16_LE(p->fp, info->bits_per_sample) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ /*
+ * Additional bytes for the extensible format.
+ *
+ * 2 bytes : Size of the extension (0 or 22)
+ * 2 bytes : Number of valid bits
+ * 4 bytes : Speaker position mask
+ * 16 bytes : GUID, including the data format code
+ */
+ if (WRITE_U16_LE(p->fp, 22) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U16_LE(p->fp, info->bits_per_sample) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U32_LE(p->fp, 0x00000000) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ static const unsigned char sub_format[16] = {
+ 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0xAA,
+ 0x00, 0x38, 0x9B, 0x71
+ };
+ for (int i = 0; i < sizeof(sub_format); i++) {
+ fputc((char)sub_format[i], p->fp);
+ }
+ }
+ break;
+ default:
+ result = WavFileResultErrorInvalidAudioFormat;
+ goto finalize;
+ }
+
+ /*
+ * [data]
+ * ------------------------------------------
+ * Big endian 4 bytes : Sub chunk ID
+ * Little endian 4 bytes : Sub chunk size
+ * ------------------------------------------
+ * Little endian 2 bytes : Sample 1 (Ch.1)
+ * Little endian 2 bytes : Sample 1 (Ch.2)
+ * .
+ * .
+ * .
+ * Little endian 2 bytes : Sample 1 (Ch.N)
+ * ------------------------------------------
+ * Little endian 2 bytes : Sample 2 (Ch.1)
+ * Little endian 2 bytes : Sample 2 (Ch.2)
+ * .
+ * .
+ * .
+ * Little endian 2 bytes : Sample 2 (Ch.N)
+ * ------------------------------------------
+ */
+ if (WRITE_U32_BE(p->fp, CHUNK_ID_DATA) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U32_LE(p->fp, 0x00000000) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+
+finalize:
+ if (WavFileResultOK == result) {
+ p->info_checked = true;
+ }
+ return result;
+}
+
+/**
+ * @details 音声データは、どんな形式でも常に0.0から1.0の範囲で正規化して入力される。
+ */
+WavFileResult wavfile_write_data(WAVFILE *p, const wavfile_data_t *data)
+{
+ WavFileResult result = WavFileResultOK;
+
+ if (p == NULL) {
+ result = WavFileResultErrorInvalidHandler;
+ goto finalize;
+ }
+
+ if (!p->info_checked) {
+ result = WavFileResultErrorNeedInfoChecked;
+ goto finalize;
+ }
+
+ if (p->mode != WavFileModeWrite) {
+ result = WavFileResultErrorInvalidMode;
+ goto finalize;
+ }
+
+ if (p->info.num_channels != data->num_channels) {
+ result = WavFileResultErrorInvalidNumChannels;
+ goto finalize;
+ }
+
+ for (int i = 0; i < p->info.num_channels; i++) {
+ switch (p->info.bits_per_sample) {
+ case BITS_PER_SAMPLE_8:
+ {
+ int n = (int)((double)data->channel_data[i] * 0xFF);
+ if (n < 0x00) {
+ n = 0x00;
+ }
+ if (0xFF < n) {
+ n = 0xFF;
+ }
+ fputc((char)n, p->fp);
+ }
+ p->data_byte_count+=1;
+ break;
+ case BITS_PER_SAMPLE_16:
+ {
+ int n = (int)((double)(data->channel_data[i] * 0xFFFF) - 0x8000);
+ if (0x7FFF < n) {
+ n = 0x7FFF;
+ }
+ if (n < -0x8000) {
+ n = -0x8000;
+ }
+ fputc(((uint16_t)n >> 0) & 0xff, p->fp);
+ fputc(((uint16_t)n >> 8) & 0xff, p->fp);
+ }
+ p->data_byte_count+=2;
+ break;
+ case BITS_PER_SAMPLE_24:
+ {
+ int n = (int)((double)(data->channel_data[i] * 0xFFFFFF) - 0x800000);
+ if (0x7FFFFF < n) {
+ n = 0x7FFFFF;
+ }
+ if (n < -0x800000) {
+ n = -0x800000;
+ }
+ fputc(((uint32_t)n >> 0) & 0xff, p->fp);
+ fputc(((uint32_t)n >> 8) & 0xff, p->fp);
+ fputc(((uint32_t)n >> 16) & 0xff, p->fp);
+ }
+ p->data_byte_count+=3;
+ break;
+ }
+ }
+ p->data_checked = true;
+
+finalize:
+ return result;
+}
+
+WavFileResult wavfile_close(WAVFILE *p)
+{
+ WavFileResult result = WavFileResultOK;
+
+ switch (p->mode) {
+ case WavFileModeRead:
+ break;
+ case WavFileModeWrite:
+ if (p->info_checked && p->data_checked) {
+ switch (p->info.audio_format) {
+ case WAVFILE_AUDIO_FORMAT_PCM:
+ {
+ /*
+ * Fill the RIFF chunk size.
+ */
+ if (fseek(p->fp, 4L, SEEK_SET) == -1) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U32_LE(p->fp, 4 + (8 + CHUNK_SIZE_FMT_PCM) + (8 + p->data_byte_count)) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+
+ /*
+ * Fill the data sub chunk size.
+ */
+ if (fseek(p->fp, 12 + (8 + CHUNK_SIZE_FMT_PCM) + 4, SEEK_SET) == -1) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U32_LE(p->fp, p->data_byte_count) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ }
+ break;
+ case WAVFILE_AUDIO_FORMAT_EXTENSIBLE:
+ {
+ /*
+ * Fill the RIFF chunk size.
+ */
+ if (fseek(p->fp, 4L, SEEK_SET) == -1) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U32_LE(p->fp, 4 + (8 + CHUNK_SIZE_FMT_EXTENSIBLE) + (8 + p->data_byte_count)) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+
+ /*
+ * Fill the data sub chunk size.
+ */
+ if (fseek(p->fp, 12 + (8 + CHUNK_SIZE_FMT_EXTENSIBLE) + 4, SEEK_SET) == -1) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ if (WRITE_U32_LE(p->fp, p->data_byte_count) != 0) {
+ result = WavFileResultErrorFileWrite;
+ goto finalize;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+finalize:
+ fclose(p->fp);
+ free(p);
+ return result;
+}
+
+void wavfile_result_string(const WavFileResult result, char *buf, size_t siz)
+{
+ switch (result) {
+ case WavFileResultOK:
+ strcpy(buf, "OK.");
+ break;
+ case WavFileResultErrorInvalidFileName:
+ strcpy(buf, "Invalid file name found.");
+ break;
+ case WavFileResultErrorMemoryAllocation:
+ strcpy(buf, "Memory allocation error.");
+ break;
+ case WavFileResultErrorFileOpen:
+ strcpy(buf, "File open error found.");
+ break;
+ case WavFileResultErrorFileWrite:
+ strcpy(buf, "File write error found.");
+ break;
+ case WavFileResultErrorBrokenChunkId:
+ strcpy(buf, "Broken chunk ID found.");
+ break;
+ case WavFileResultErrorBrokenChunkSize:
+ strcpy(buf, "Borken chunk size found.");
+ break;
+ case WavFileResultErrorBrokenChunkData:
+ strcpy(buf, "Borken chunk data found.");
+ break;
+ case WavFileResultErrorBrokenFormatId:
+ strcpy(buf, "Broken format ID found.");
+ break;
+ case WavFileResultErrorInvalidFormatId:
+ strcpy(buf, "Invalid format ID found.");
+ break;
+ case WavFileResultErrorBrokenAudioFormat:
+ strcpy(buf, "Broken audio format found.");
+ break;
+ case WavFileResultErrorInvalidAudioFormat:
+ strcpy(buf, "Invalid audio format found.");
+ break;
+ case WavFileResultErrorInvalidNumChannels:
+ strcpy(buf, "Invalid number of channels found.");
+ break;
+ case WavFileResultErrorBrokenNumChannels:
+ strcpy(buf, "Broken number of channels found.");
+ break;
+ case WavFileResultErrorBrokenSampleRate:
+ strcpy(buf, "Broken sample rate found.");
+ break;
+ case WavFileResultErrorBrokenByteRate:
+ strcpy(buf, "Broken byte rate found.");
+ break;
+ case WavFileResultErrorInvalidByteRate:
+ strcpy(buf, "Invalid byte rate found.");
+ break;
+ case WavFileResultErrorBrokenBlockAlign:
+ strcpy(buf, "Broken block alignment found.");
+ break;
+ case WavFileResultErrorBrokenBitsPerSample:
+ strcpy(buf, "Broken bits per sample found.");
+ break;
+ case WavFileResultErrorUnsupportedBitsPerSample:
+ strcpy(buf, "Unsupported bits per sample found.");
+ break;
+ case WavFileResultErrorAlreadyInfoChecked:
+ strcpy(buf, "Already checked info.");
+ break;
+ case WavFileResultErrorAlreadyDataChecked:
+ strcpy(buf, "Already checked data.");
+ break;
+ case WavFileResultErrorNoDataChunk:
+ strcpy(buf, "No data chunk.");
+ break;
+ case WavFileResultErrorInvalidMode:
+ strcpy(buf, "Invalid mode.");
+ break;
+ case WavFileResultErrorNeedInfoChecked:
+ strcpy(buf, "Need check info.");
+ break;
+ case WavFileResultErrorNeedDataChecked:
+ strcpy(buf, "Need check data.");
+ break;
+ case WavFileResultErrorInvalidHandler:
+ strcpy(buf, "Invalid handler.");
+ break;
+ default:
+ strcpy(buf, "Unkonwn error found.");
+ break;
+ }
+}
+
--- /dev/null
+/**
+ * @file wavfile.h
+ * @author Shinichiro Nakamura
+ * @brief libcベースのWAVファイルモジュール。
+ */
+
+/*
+ * ===============================================================
+ * Tiny WAV I/O Module
+ * Version 0.0.1
+ * ===============================================================
+ * Copyright (c) 2011-2012 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#ifndef WAVFILE_H
+#define WAVFILE_H
+
+#include <stdio.h>
+#include <stdint.h>
+
+#define WAVFILE_AUDIO_FORMAT_PCM (1)
+#define WAVFILE_AUDIO_FORMAT_EXTENSIBLE (65534)
+#define WAVFILE_MAXIMUM_CHANNELS (32)
+
+#define WAVFILE_INFO_AUDIO_FORMAT(P) ((P)->audio_format)
+#define WAVFILE_INFO_NUM_CHANNELS(P) ((P)->num_channels)
+#define WAVFILE_INFO_SAMPLE_RATE(P) ((P)->sample_rate)
+#define WAVFILE_INFO_BYTE_RATE(P) ((P)->byte_rate)
+#define WAVFILE_INFO_BLOCK_ALIGN(P) ((P)->block_align)
+#define WAVFILE_INFO_BITS_PER_SAMPLE(P) ((P)->bits_per_sample)
+
+#define WAVFILE_DATA_IS_END_OF_DATA(P) ((P)->num_channels == 0)
+#define WAVFILE_DATA_NUM_CHANNELS(P) ((P)->num_channels)
+#define WAVFILE_DATA_CHANNEL_DATA(P,CH) ((P)->channel_data[CH])
+
+#define WAVFILE_DEBUG_ENABLED (0)
+
+typedef struct WAVFILE WAVFILE;
+
+typedef struct {
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate;
+ uint16_t block_align;
+ uint16_t bits_per_sample;
+} wavfile_info_t;
+
+typedef struct {
+ uint16_t num_channels;
+ double channel_data[WAVFILE_MAXIMUM_CHANNELS];
+} wavfile_data_t;
+
+/**
+ * @brief エラーコード。
+ */
+enum WavFileResult {
+ WavFileResultOK,
+ WavFileResultErrorInvalidFileName,
+ WavFileResultErrorMemoryAllocation,
+ WavFileResultErrorFileOpen,
+ WavFileResultErrorFileWrite,
+ WavFileResultErrorBrokenChunkId,
+ WavFileResultErrorBrokenChunkSize,
+ WavFileResultErrorBrokenChunkData,
+ WavFileResultErrorBrokenFormatId,
+ WavFileResultErrorInvalidFormatId,
+ WavFileResultErrorBrokenAudioFormat,
+ WavFileResultErrorInvalidAudioFormat,
+ WavFileResultErrorInvalidNumChannels,
+ WavFileResultErrorBrokenNumChannels,
+ WavFileResultErrorBrokenSampleRate,
+ WavFileResultErrorBrokenByteRate,
+ WavFileResultErrorInvalidByteRate,
+ WavFileResultErrorBrokenBlockAlign,
+ WavFileResultErrorBrokenBitsPerSample,
+ WavFileResultErrorUnsupportedBitsPerSample,
+ WavFileResultErrorAlreadyInfoChecked,
+ WavFileResultErrorAlreadyDataChecked,
+ WavFileResultErrorNoDataChunk,
+ WavFileResultErrorInvalidMode,
+ WavFileResultErrorNeedInfoChecked,
+ WavFileResultErrorNeedDataChecked,
+ WavFileResultErrorInvalidHandler,
+};
+
+/**
+ * @brief ファイルモード。
+ */
+enum WavFileMode {
+ WavFileModeRead, /**< ファイルは読み込みモード。 */
+ WavFileModeWrite, /**< ファイルは書き込みモード。 */
+};
+
+WAVFILE *wavfile_open(const char *filename, WavFileMode mode, WavFileResult *result);
+WavFileResult wavfile_read_info(WAVFILE *p, wavfile_info_t *info);
+WavFileResult wavfile_read_data(WAVFILE *p, wavfile_data_t *data);
+WavFileResult wavfile_write_info(WAVFILE *p, const wavfile_info_t *info);
+WavFileResult wavfile_write_data(WAVFILE *p, const wavfile_data_t *data);
+WavFileResult wavfile_close(WAVFILE *p);
+void wavfile_result_string(const WavFileResult result, char *buf, size_t siz);
+
+#endif
+