This commit is contained in:
89
.github/workflows/ci.yaml
vendored
Normal file
89
.github/workflows/ci.yaml
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [trunk]
|
||||
pull_request:
|
||||
branches: [trunk]
|
||||
|
||||
jobs:
|
||||
build-and-analyze:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install tools
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y build-essential clang clang-tools clang-tidy cppcheck gcc-mingw-w64-x86-64 cmake
|
||||
|
||||
- name: Build with GCC
|
||||
run: |
|
||||
make -f Makefile.posix clean
|
||||
make -f Makefile.posix CC=gcc CFLAGS="-std=c99 -Wall -Wextra -Wpedantic -Werror -O2"
|
||||
|
||||
- name: Build with Clang
|
||||
run: |
|
||||
make -f Makefile.posix clean
|
||||
make -f Makefile.posix CC=clang CFLAGS="-std=c99 -Wall -Wextra -Wpedantic -Werror -O2"
|
||||
|
||||
- name: Build with MinGW
|
||||
run: |
|
||||
make -f Makefile.posix clean
|
||||
make -f Makefile.mingw CC=x86_64-w64-mingw32-gcc AR=x86_64-w64-mingw32-ar CFLAGS="-std=c99 -Wall -Wextra -Wpedantic -Werror -O2"
|
||||
|
||||
- name: Build with CMake
|
||||
run: |
|
||||
cmake -S . -B build
|
||||
cmake --build build
|
||||
|
||||
- name: Linting checks
|
||||
run: |
|
||||
echo "Running all linting checks..."
|
||||
FAILED=0
|
||||
|
||||
# cppcheck
|
||||
echo "=== Check 1/4: cppcheck ==="
|
||||
if make -f Makefile.lint cppcheck; then
|
||||
echo "cppcheck: PASSED"
|
||||
else
|
||||
echo "cppcheck: FAILED"
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
# clang-tidy
|
||||
echo "=== Check 2/4: clang-tidy ==="
|
||||
if make -f Makefile.lint clang-tidy; then
|
||||
echo "clang-tidy: PASSED"
|
||||
else
|
||||
echo "clang-tidy: FAILED"
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
# scan-build
|
||||
echo "=== Check 3/4: scan-build ==="
|
||||
if make -f Makefile.lint scan-build; then
|
||||
echo "scan-build: PASSED"
|
||||
else
|
||||
echo "scan-build: FAILED"
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
# security-check
|
||||
echo "=== Check 4/4: security-check ==="
|
||||
if make -f Makefile.lint security-check; then
|
||||
echo "security-check: PASSED"
|
||||
else
|
||||
echo "security-check: FAILED"
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
# Final result
|
||||
if [ $FAILED -ne 0 ]; then
|
||||
echo "One or more linting checks failed."
|
||||
exit 1
|
||||
else
|
||||
echo "All linting checks passed."
|
||||
fi
|
||||
68
.gitignore
vendored
Normal file
68
.gitignore
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
# ---> C
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
# ---> CMake
|
||||
CMakeLists.txt.user
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Testing
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
CMakeUserPresets.json
|
||||
|
||||
25
CMakeLists.txt
Normal file
25
CMakeLists.txt
Normal file
@@ -0,0 +1,25 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(CgeSample LANGUAGES C)
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
set(SOURCES
|
||||
Sample.c
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
CgeSample.h
|
||||
)
|
||||
|
||||
add_library(CgeSample STATIC ${SOURCES} ${HEADERS})
|
||||
|
||||
target_include_directories(CgeSample PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
install(TARGETS CgeSample
|
||||
ARCHIVE DESTINATION lib
|
||||
LIBRARY DESTINATION lib
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
|
||||
install(FILES ${HEADERS} DESTINATION include)
|
||||
46
CgeSample.h
Normal file
46
CgeSample.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef CGE_SAMPLE_H
|
||||
#define CGE_SAMPLE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
enum CgeSampleFormat {
|
||||
CGE_SAMPLE_UNKNOWN, /* Invalid or unknown format */
|
||||
CGE_SAMPLE_S8, /* 8-bit signed integer, range: -128 to 127 */
|
||||
CGE_SAMPLE_U8, /* 8-bit unsigned integer, range: 0 to 255 */
|
||||
CGE_SAMPLE_S16, /* 16-bit signed integer, range: -32768 to 32767 */
|
||||
CGE_SAMPLE_U16, /* 16-bit unsigned integer, range: 0 to 65535 */
|
||||
CGE_SAMPLE_S24, /* 24-bit signed integer */
|
||||
CGE_SAMPLE_U24, /* 24-bit unsigned integer */
|
||||
CGE_SAMPLE_S32, /* 32-bit signed integer */
|
||||
CGE_SAMPLE_U32, /* 32-bit unsigned integer */
|
||||
CGE_SAMPLE_F32, /* 32-bit IEEE 754 float */
|
||||
CGE_SAMPLE_F64, /* 64-bit IEEE 754 double */
|
||||
};
|
||||
|
||||
typedef struct CgeSampleBuf {
|
||||
void *data;
|
||||
int format;
|
||||
size_t count;
|
||||
size_t stride;
|
||||
} CgeSampleBuf;
|
||||
|
||||
size_t CgeSampleInitLayout(CgeSampleBuf *buf, int format, size_t count);
|
||||
float CgeSampleGetF32(const CgeSampleBuf *buf, size_t index);
|
||||
void CgeSampleSetF32(CgeSampleBuf *buf, size_t index, float value);
|
||||
int16_t CgeSampleGetS16(const CgeSampleBuf *buf, size_t index);
|
||||
void CgeSampleSetS16(CgeSampleBuf *buf, size_t index, int16_t value);
|
||||
|
||||
void CgeSampleConvert(void *src, int srcFormat, size_t srcStride,
|
||||
void *dst, int dstFormat, size_t dstStride,
|
||||
size_t count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CGE_SAMPLE_H */
|
||||
12
LICENSE
Normal file
12
LICENSE
Normal file
@@ -0,0 +1,12 @@
|
||||
Copyright (C) 2026 by blankhex me@blankhex.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
29
Makefile.lint
Normal file
29
Makefile.lint
Normal file
@@ -0,0 +1,29 @@
|
||||
# Makefile.lint - Individual linting targets
|
||||
|
||||
.PHONY: all
|
||||
all: cppcheck clang-tidy scan-build security-check
|
||||
@echo "All linting scheduled"
|
||||
|
||||
.PHONY: cppcheck
|
||||
cppcheck:
|
||||
@echo "Running cppcheck..."
|
||||
@cppcheck --enable=warning,performance,portability --std=c99 --quiet -Iinclude -I. .
|
||||
|
||||
.PHONY: clang-tidy
|
||||
clang-tidy:
|
||||
@echo "Running clang-tidy..."
|
||||
@for file in $$(find . -name "*.c" -type f); do \
|
||||
clang-tidy "$$file" -- -I. -Iinclude -std=c99; \
|
||||
done
|
||||
|
||||
.PHONY: scan-build
|
||||
scan-build:
|
||||
@echo "Running scan-build..."
|
||||
@scan-build --status-bugs make -f Makefile.posix clean all CC=clang
|
||||
|
||||
.PHONY: security-check
|
||||
security-check:
|
||||
@echo "Scanning for unsafe C functions..."
|
||||
@grep -rnE '\b(strcpy|strcat|sprintf|gets|scanf|sscanf|realpath|mktemp|tempnam|tmpnam|getwd|getlogin)\b' \
|
||||
. --include="*.c" --include="*.h" | grep -v "^Binary file" && \
|
||||
exit 1 || exit 0
|
||||
23
Makefile.mingw
Normal file
23
Makefile.mingw
Normal file
@@ -0,0 +1,23 @@
|
||||
# MinGW Makefile for CgeSample
|
||||
|
||||
CC = gcc
|
||||
AR = ar
|
||||
CFLAGS = -std=c99 -O2 -Wall -Wextra
|
||||
ARFLAGS = rcs
|
||||
TARGET = libCgeSample.a
|
||||
|
||||
SOURCES = Sample.c
|
||||
OBJECTS = $(SOURCES:.c=.o)
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJECTS)
|
||||
$(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
%.o: %.c CgeSample.h
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
del $(OBJECTS) $(TARGET) 2>nul || exit 0
|
||||
33
Makefile.posix
Normal file
33
Makefile.posix
Normal file
@@ -0,0 +1,33 @@
|
||||
# POSIX Makefile for CgeSample
|
||||
|
||||
CC = gcc
|
||||
AR = ar
|
||||
CFLAGS = -std=c99 -O2 -Wall -Wextra -fPIC
|
||||
ARFLAGS = rcs
|
||||
TARGET = libCgeSample.a
|
||||
|
||||
SOURCES = Sample.c
|
||||
OBJECTS = $(SOURCES:.c=.o)
|
||||
|
||||
.PHONY: all clean install
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJECTS)
|
||||
$(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
%.o: %.c CgeSample.h
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJECTS) $(TARGET)
|
||||
|
||||
install: $(TARGET)
|
||||
cp $(TARGET) /usr/local/lib/
|
||||
cp CgeSample.h /usr/local/include/
|
||||
ldconfig || echo "Run ldconfig manually if needed"
|
||||
|
||||
uninstall:
|
||||
rm -f /usr/local/lib/libCgeSample.a
|
||||
rm -f /usr/local/include/CgeSample.h
|
||||
ldconfig || true
|
||||
23
Makefile.win32
Normal file
23
Makefile.win32
Normal file
@@ -0,0 +1,23 @@
|
||||
# Makefile.win32 for MSVC (NMake)
|
||||
# Usage: Open "x86 Native Tools Command Prompt", then:
|
||||
# nmake -f Makefile.win32
|
||||
|
||||
CC = cl
|
||||
LIB = lib
|
||||
CFLAGS = /c /nologo /W3 /O2
|
||||
LIBFLAGS = /nologo
|
||||
TARGET = CgeSample.lib
|
||||
|
||||
SOURCES = Sample.c
|
||||
OBJECTS = $(SOURCES:.c=.obj)
|
||||
|
||||
$(TARGET): $(OBJECTS)
|
||||
$(LIB) $(LIBFLAGS) /OUT:$(TARGET) $(OBJECTS)
|
||||
|
||||
{.}.c{}.obj:
|
||||
$(CC) $(CFLAGS) /Fo$@ $<
|
||||
|
||||
clean:
|
||||
del $(OBJECTS) $(TARGET) 2>nul
|
||||
|
||||
.PHONY: clean
|
||||
7
README.md
Normal file
7
README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# CgeSample
|
||||
|
||||
TODO
|
||||
|
||||
## License
|
||||
|
||||
0BSD - a permissive license with no attribution required.
|
||||
338
Sample.c
Normal file
338
Sample.c
Normal file
@@ -0,0 +1,338 @@
|
||||
#include "CgeSample.h"
|
||||
#include <string.h>
|
||||
|
||||
static size_t bytesPerSample(int format) {
|
||||
switch (format) {
|
||||
default:
|
||||
return 0;
|
||||
|
||||
case CGE_SAMPLE_U8:
|
||||
case CGE_SAMPLE_S8:
|
||||
return 1;
|
||||
|
||||
case CGE_SAMPLE_U16:
|
||||
case CGE_SAMPLE_S16:
|
||||
return 2;
|
||||
|
||||
case CGE_SAMPLE_U24:
|
||||
case CGE_SAMPLE_S24:
|
||||
case CGE_SAMPLE_U32:
|
||||
case CGE_SAMPLE_S32:
|
||||
case CGE_SAMPLE_F32:
|
||||
return 4;
|
||||
|
||||
case CGE_SAMPLE_F64:
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
size_t CgeSampleInitLayout(CgeSampleBuf *buf, int format, size_t count) {
|
||||
buf->count = count;
|
||||
buf->format = format;
|
||||
buf->data = NULL;
|
||||
buf->stride = bytesPerSample(format);
|
||||
|
||||
return buf->stride * count;
|
||||
}
|
||||
|
||||
float CgeSampleGetF32(const CgeSampleBuf *buf, size_t index) {
|
||||
void *data;
|
||||
|
||||
data = (char *)buf->data + index * buf->stride;
|
||||
switch (buf->format) {
|
||||
default:
|
||||
case CGE_SAMPLE_UNKNOWN: return 0.0f;
|
||||
case CGE_SAMPLE_S8: return (float)(*(int8_t*)data) / 128.0f;
|
||||
case CGE_SAMPLE_U8: return ((float)(*(uint8_t*)data) - 128.0f) / 128.0f;
|
||||
case CGE_SAMPLE_S16: return (float)(*(int16_t*)data) / 32768.0f;
|
||||
case CGE_SAMPLE_U16: return ((float)(*(uint16_t*)data) - 32768.0f) / 32768.0f;
|
||||
case CGE_SAMPLE_S24: return (float)(*(int32_t*)data) / 8388608.0f;
|
||||
case CGE_SAMPLE_U24: return ((float)(*(uint32_t*)data) - 8388608.0f) / 8388608.0f;
|
||||
case CGE_SAMPLE_S32: return (float)(*(int32_t*)data) / 2147483648.0f;
|
||||
case CGE_SAMPLE_U32: return ((float)(*(uint32_t*)data) - 2147483648.0f) / 2147483648.0f;
|
||||
case CGE_SAMPLE_F32: return (*(float*)data);
|
||||
case CGE_SAMPLE_F64: return (*(double*)data);
|
||||
}
|
||||
}
|
||||
|
||||
void CgeSampleSetF32(CgeSampleBuf *buf, size_t index, float value) {
|
||||
void *data;
|
||||
|
||||
data = (char *)buf->data + index * buf->stride;
|
||||
switch (buf->format) {
|
||||
default:
|
||||
case CGE_SAMPLE_UNKNOWN:
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_S8:
|
||||
value *= 128.0f;
|
||||
value += (value >= 0.0f) ? 0.5f : -0.5f;
|
||||
if (value > 127.0f) value = 127.0f;
|
||||
if (value < -128.0f) value = -128.0f;
|
||||
*(int8_t*)data = value;
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_U8:
|
||||
value = value * 128.0f + 128.0f;
|
||||
value += (value >= 0.0f) ? 0.5f : -0.5f;
|
||||
if (value > 255.0f) value = 255.0f;
|
||||
if (value < 0.0f) value = 0.0f;
|
||||
*(uint8_t*)data = value;
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_S16:
|
||||
value *= 32768.0f;
|
||||
value += (value >= 0.0f) ? 0.5f : -0.5f;
|
||||
if (value > 32767.0f) value = 32767.0f;
|
||||
if (value < -32768.0f) value = -32768.0f;
|
||||
*(int16_t*)data = value;
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_U16:
|
||||
value = value * 32768.0f + 32768.0f;
|
||||
value += (value >= 0.0f) ? 0.5f : -0.5f;
|
||||
if (value > 65535.0f) value = 65535.0f;
|
||||
if (value < 0.0f) value = 0.0f;
|
||||
*(uint16_t*)data = value;
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_S24:
|
||||
value *= 8388608.0f;
|
||||
value += (value >= 0.0f) ? 0.5f : -0.5f;
|
||||
if (value > 8388607.0f) value = 8388607.0f;
|
||||
if (value < -8388608.0f) value = -8388608.0f;
|
||||
*(int32_t*)data = value;
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_U24:
|
||||
value = value * 8388608.0f + 8388608.0f;
|
||||
value += (value >= 0.0f) ? 0.5f : -0.5f;
|
||||
if (value > 16777215.0f) value = 16777215.0f;
|
||||
if (value < 0.0f) value = 0.0f;
|
||||
*(uint32_t*)data = value;
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_S32: {
|
||||
double scaled = value;
|
||||
scaled *= 2147483648.0;
|
||||
scaled += (scaled >= 0.0) ? 0.5 : -0.5;
|
||||
if (scaled > 2147483647.0) scaled = 2147483647.0;
|
||||
if (scaled < -2147483648.0) scaled = -2147483648.0;
|
||||
*(int32_t*)data = scaled;
|
||||
break;
|
||||
}
|
||||
|
||||
case CGE_SAMPLE_U32: {
|
||||
double scaled = value;
|
||||
scaled = scaled * 2147483648.0 + 2147483648.0;
|
||||
scaled += (scaled >= 0.0) ? 0.5 : -0.5;
|
||||
if (scaled > 4294967295.0) scaled = 4294967295.0;
|
||||
if (scaled < 0.0) scaled = 0.0;
|
||||
*(uint32_t*)data = scaled;
|
||||
break;
|
||||
}
|
||||
|
||||
case CGE_SAMPLE_F32:
|
||||
*(float*)data = value;
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_F64:
|
||||
*(double*)data = (double)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t CgeSampleGetS16(const CgeSampleBuf *buf, size_t index) {
|
||||
void *data;
|
||||
|
||||
data = (char *)buf->data + index * buf->stride;
|
||||
switch (buf->format) {
|
||||
default:
|
||||
case CGE_SAMPLE_UNKNOWN: return 0;
|
||||
case CGE_SAMPLE_S8: return (int16_t)*(int8_t*)data * 256;
|
||||
case CGE_SAMPLE_U8: return ((int16_t)*(uint8_t*)data - 128) * 256;
|
||||
case CGE_SAMPLE_S16: return *(int16_t*)data;
|
||||
case CGE_SAMPLE_U16: return ((uint32_t)*(uint16_t*)data - 32768);
|
||||
case CGE_SAMPLE_S24: return (*(int32_t*)data / 256);
|
||||
case CGE_SAMPLE_U24: return ((*(uint32_t*)data / 256) - 32768);
|
||||
case CGE_SAMPLE_S32: return (*(int32_t*)data / 65536);
|
||||
case CGE_SAMPLE_U32: return ((*(uint32_t*)data / 65536) - 32768);
|
||||
case CGE_SAMPLE_F32: {
|
||||
float value = *(float*)data;
|
||||
value *= 32768.0f;
|
||||
value += (value >= 0.0f) ? 0.5f : -0.5f;
|
||||
if (value > 32767.0f) value = 32767.0f;
|
||||
if (value < -32768.0f) value = -32768.0f;
|
||||
return (int16_t)value;
|
||||
}
|
||||
case CGE_SAMPLE_F64: {
|
||||
float value = (float)(*(double*)data);
|
||||
value *= 32768.0;
|
||||
value += (value >= 0.0) ? 0.5 : -0.5;
|
||||
if (value > 32767.0) value = 32767.0;
|
||||
if (value < -32768.0) value = -32768.0;
|
||||
return (int16_t)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CgeSampleSetS16(CgeSampleBuf *buf, size_t index, int16_t value) {
|
||||
void *data;
|
||||
int32_t scaled;
|
||||
uint32_t unscaled;
|
||||
|
||||
data = (char *)buf->data + index * buf->stride;
|
||||
switch (buf->format) {
|
||||
default:
|
||||
case CGE_SAMPLE_UNKNOWN:
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_S8:
|
||||
*(int8_t*)data = (int8_t)(value / 256);
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_U8:
|
||||
*(uint8_t*)data = (uint8_t)(value / 256 + 128);
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_S16:
|
||||
*(int16_t*)data = value;
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_U16:
|
||||
*(uint16_t*)data = (uint16_t)((int32_t)value + 32768);
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_S24:
|
||||
scaled = (int32_t)value * 256;
|
||||
if (scaled > 8388607) scaled = 8388607;
|
||||
if (scaled < -8388608) scaled = -8388608;
|
||||
*(int32_t*)data = scaled;
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_U24:
|
||||
scaled = (((int32_t)value + 32768) & 0xFFFF) * 256;
|
||||
if (scaled > 16777215) scaled = 16777215;
|
||||
*(uint32_t*)data = (uint32_t)scaled;
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_S32:
|
||||
*(int32_t*)data = (int32_t)value * 65536;
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_U32:
|
||||
unscaled = (((uint32_t)((int32_t)value + 32768)) & 0xFFFFu) * 65536u;
|
||||
*(uint32_t*)data = unscaled;
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_F32:
|
||||
*(float*)data = (float)value / 32768.0f;
|
||||
break;
|
||||
|
||||
case CGE_SAMPLE_F64:
|
||||
*(double*)data = (double)value / 32768.0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void fastCopy(void *src, size_t srcStride, void *dst,
|
||||
size_t dstStride, size_t count, size_t size) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
memcpy(dst, src, size);
|
||||
src = (char*)src + srcStride;
|
||||
dst = (char*)dst + dstStride;
|
||||
}
|
||||
}
|
||||
|
||||
static void fastS16ToF32(void *src, size_t srcStride, void *dst,
|
||||
size_t dstStride, size_t count) {
|
||||
const float scale = 1.0f / 32768.0f;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
*(float *)dst = *(int16_t *)src * scale;
|
||||
src = (char *)src + srcStride;
|
||||
dst = (char *)dst + dstStride;
|
||||
}
|
||||
}
|
||||
|
||||
static void fastF32ToS16(void *src, size_t srcStride, void *dst,
|
||||
size_t dstStride, size_t count) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
int32_t v = (int32_t)(*(float *)src * 32768.0f);
|
||||
|
||||
if (v > 32767)
|
||||
v = 32767;
|
||||
else if (v < -32768)
|
||||
v = -32768;
|
||||
|
||||
*(int16_t *)dst = (int16_t)v;
|
||||
src = (void *)((char *)src + srcStride);
|
||||
dst = (void *)((char *)dst + dstStride);
|
||||
}
|
||||
}
|
||||
|
||||
static void fastS24ToF32(void *src, size_t srcStride, void *dst,
|
||||
size_t dstStride, size_t count) {
|
||||
const float scale = 1.0f / 8388608.0f;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
*(float *)dst = *(int32_t *)src * scale;
|
||||
src = (void *)((char *)src + srcStride);
|
||||
dst = (void *)((char *)dst + dstStride);
|
||||
}
|
||||
}
|
||||
|
||||
static void fastF32ToS24(void *src, size_t srcStride, void *dst,
|
||||
size_t dstStride, size_t count) {
|
||||
size_t i;
|
||||
for (i = 0; i < count; i++) {
|
||||
int32_t v = (int32_t)(*(float *)src * 8388608.0f);
|
||||
|
||||
if (v > 8388607)
|
||||
v = 8388607;
|
||||
else if (v < -8388608)
|
||||
v = -8388608;
|
||||
|
||||
*(int32_t *)dst = (int32_t)v;
|
||||
src = (void *)((char *)src + srcStride);
|
||||
dst = (void *)((char *)dst + dstStride);
|
||||
}
|
||||
}
|
||||
|
||||
void CgeSampleConvert(void *src, int srcFormat, size_t srcStride,
|
||||
void *dst, int dstFormat, size_t dstStride,
|
||||
size_t count) {
|
||||
CgeSampleBuf srcBuf, dstBuf;
|
||||
size_t i;
|
||||
|
||||
srcStride = (srcStride) ? (srcStride) : bytesPerSample(srcFormat);
|
||||
dstStride = (dstStride) ? (dstStride) : bytesPerSample(dstFormat);
|
||||
|
||||
if (srcFormat == dstFormat) {
|
||||
fastCopy(src, srcStride, dst, dstStride, count, bytesPerSample(srcFormat));
|
||||
} else if (srcFormat == CGE_SAMPLE_S16 && dstFormat == CGE_SAMPLE_F32) {
|
||||
fastS16ToF32(src, srcStride, dst, dstStride, count);
|
||||
} else if (srcFormat == CGE_SAMPLE_F32 && dstFormat == CGE_SAMPLE_S16) {
|
||||
fastF32ToS16(src, srcStride, dst, dstStride, count);
|
||||
} else if (srcFormat == CGE_SAMPLE_F32 && dstFormat == CGE_SAMPLE_S24) {
|
||||
fastF32ToS24(src, srcStride, dst, dstStride, count);
|
||||
} else if (srcFormat == CGE_SAMPLE_S24 && dstFormat == CGE_SAMPLE_F32) {
|
||||
fastS24ToF32(src, srcStride, dst, dstStride, count);
|
||||
} else {
|
||||
CgeSampleInitLayout(&srcBuf, srcFormat, count);
|
||||
CgeSampleInitLayout(&dstBuf, dstFormat, count);
|
||||
srcBuf.stride = srcStride;
|
||||
dstBuf.stride = dstStride;
|
||||
srcBuf.data = src;
|
||||
dstBuf.data = dst;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
CgeSampleSetF32(&dstBuf, i, CgeSampleGetF32(&srcBuf, i));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user