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