docs: add more documentation to each of the modules in vlib (#13043)
parent
287331bc19
commit
6e6d51a1c9
|
@ -1 +1,8 @@
|
|||
# Documentation for all included modules...
|
||||
# `vlib` Documentation
|
||||
|
||||
`vlib` is the term for all modules included by default with V and
|
||||
maintained as part of the V source code repository.
|
||||
|
||||
Some included modules depend on third party libraries, and these are kept
|
||||
separate in the `thirdparty` directory at the root level of the source
|
||||
repository.
|
||||
|
|
|
@ -1,4 +1,16 @@
|
|||
## Description:
|
||||
|
||||
`arrays` provides some generic functions for processing arrays.
|
||||
`arrays` is a module that provides utility functions to make working with arrays easier.
|
||||
|
||||
## Examples:
|
||||
|
||||
```v
|
||||
import arrays
|
||||
|
||||
fn main() {
|
||||
a := [1, 5, 7, 0, 9]
|
||||
assert arrays.min(a) ? == 0
|
||||
assert arrays.max(a) ? == 9
|
||||
assert arrays.idx_min(a) ? == 3
|
||||
}
|
||||
```
|
||||
|
|
|
@ -6,9 +6,10 @@ module arrays
|
|||
// - merge - combine two sorted arrays and maintain sorted order
|
||||
// - chunk - chunk array to arrays with n elements
|
||||
// - window - get snapshots of the window of the given size sliding along array with the given step, where each snapshot is an array
|
||||
// - zip - concat two arrays into one map
|
||||
// - TODO: zip - merge two arrays by interleaving e.g. arrays.zip([1,3,5], [2,4,6]) => [1,2,3,4,5,6]
|
||||
|
||||
// min returns the minimum value in the array
|
||||
// Example: arrays.min([1,2,3,0,9]) // => 0
|
||||
pub fn min<T>(a []T) ?T {
|
||||
if a.len == 0 {
|
||||
return error('.min called on an empty array')
|
||||
|
@ -23,6 +24,7 @@ pub fn min<T>(a []T) ?T {
|
|||
}
|
||||
|
||||
// max returns the maximum the maximum value in the array
|
||||
// Example: arrays.max([1,2,3,0,9]) // => 9
|
||||
pub fn max<T>(a []T) ?T {
|
||||
if a.len == 0 {
|
||||
return error('.max called on an empty array')
|
||||
|
@ -37,6 +39,7 @@ pub fn max<T>(a []T) ?T {
|
|||
}
|
||||
|
||||
// idx_min returns the index of the minimum value in the array
|
||||
// Example: arrays.idx_min([1,2,3,0,9]) // => 3
|
||||
pub fn idx_min<T>(a []T) ?int {
|
||||
if a.len == 0 {
|
||||
return error('.idx_min called on an empty array')
|
||||
|
@ -53,6 +56,7 @@ pub fn idx_min<T>(a []T) ?int {
|
|||
}
|
||||
|
||||
// idx_max returns the index of the maximum value in the array
|
||||
// Example: arrays.idx_max([1,2,3,0,9]) // => 4
|
||||
pub fn idx_max<T>(a []T) ?int {
|
||||
if a.len == 0 {
|
||||
return error('.idx_max called on an empty array')
|
||||
|
@ -69,6 +73,7 @@ pub fn idx_max<T>(a []T) ?int {
|
|||
}
|
||||
|
||||
// merge two sorted arrays (ascending) and maintain sorted order
|
||||
// Example: arrays.merge([1,3,5,7], [2,4,6,8]) // => [1,2,3,4,5,6,7,8]
|
||||
[direct_array_access]
|
||||
pub fn merge<T>(a []T, b []T) []T {
|
||||
mut m := []T{len: a.len + b.len}
|
||||
|
@ -102,6 +107,8 @@ pub fn merge<T>(a []T, b []T) []T {
|
|||
}
|
||||
|
||||
// group n arrays into a single array of arrays with n elements
|
||||
// (an error will be generated if the type annotation is omitted)
|
||||
// Example: arrays.group<int>([1,2,3],[4,5,6]) // => [[1, 4], [2, 5], [3, 6]]
|
||||
pub fn group<T>(lists ...[]T) [][]T {
|
||||
mut length := if lists.len > 0 { lists[0].len } else { 0 }
|
||||
// calculate length of output by finding shortest input array
|
||||
|
@ -128,8 +135,8 @@ pub fn group<T>(lists ...[]T) [][]T {
|
|||
return [][]T{}
|
||||
}
|
||||
|
||||
// chunk array to arrays with n elements
|
||||
// example: arrays.chunk([1, 2, 3], 2) => [[1, 2], [3]]
|
||||
// chunk array into a single array of arrays where each element is the next `size` elements of the original
|
||||
// Example: arrays.chunk([1, 2, 3, 4, 5, 6, 7, 8, 9], 2)) // => [[1, 2], [3, 4], [5, 6], [7, 8], [9]]
|
||||
pub fn chunk<T>(list []T, size int) [][]T {
|
||||
// allocate chunk array
|
||||
mut chunks := [][]T{cap: list.len / size + if list.len % size == 0 { 0 } else { 1 }}
|
||||
|
@ -163,8 +170,8 @@ pub struct WindowAttribute {
|
|||
// - `size` - snapshot size
|
||||
// - `step` - gap size between each snapshot, default is 1.
|
||||
//
|
||||
// example A: `arrays.window([1, 2, 3, 4], size: 2)` => `[[1, 2], [2, 3], [3, 4]]`
|
||||
// example B: `arrays.window([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], size: 3, step: 2)` => `[[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9]]`
|
||||
// Example: arrays.window([1, 2, 3, 4], size: 2) => [[1, 2], [2, 3], [3, 4]]
|
||||
// Example: arrays.window([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], size: 3, step: 2) // => [[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9]]
|
||||
pub fn window<T>(list []T, attr WindowAttribute) [][]T {
|
||||
// allocate snapshot array
|
||||
mut windows := [][]T{cap: list.len - attr.size + 1}
|
||||
|
@ -183,10 +190,11 @@ pub fn window<T>(list []T, attr WindowAttribute) [][]T {
|
|||
}
|
||||
|
||||
// sum up array, return nothing when array has no elements
|
||||
// NOTICE: currently V has bug that cannot make sum function takes custom struct with + operator overloaded.
|
||||
//
|
||||
// NOTICE: currently V has bug that cannot make sum function takes custom struct with + operator overloaded
|
||||
// which means you can only pass array of numbers for now.
|
||||
// Future work: Fix generic operator overloading detection issue.
|
||||
// usage: `arrays.sum<int>([1, 2, 3, 4, 5])?` => `15`
|
||||
// TODO: Fix generic operator overloading detection issue.
|
||||
// Example: arrays.sum<int>([1, 2, 3, 4, 5])? // => 15
|
||||
pub fn sum<T>(list []T) ?T {
|
||||
if list.len == 0 {
|
||||
return error('Cannot sum up array of nothing.')
|
||||
|
@ -206,8 +214,8 @@ pub fn sum<T>(list []T) ?T {
|
|||
}
|
||||
|
||||
// accumulates values with the first element and applying providing operation to current accumulator value and each elements.
|
||||
// if the array is empty, then returns error.
|
||||
// usage: `arrays.reduce([1, 2, 3, 4, 5], fn (t1 int, t2 int) int { return t1 * t2 })?` => `120`
|
||||
// If the array is empty, then returns error.
|
||||
// Example: arrays.reduce([1, 2, 3, 4, 5], fn (t1 int, t2 int) int { return t1 * t2 })? // => 120
|
||||
pub fn reduce<T>(list []T, reduce_op fn (t1 T, t2 T) T) ?T {
|
||||
if list.len == 0 {
|
||||
return error('Cannot reduce array of nothing.')
|
||||
|
@ -227,7 +235,7 @@ pub fn reduce<T>(list []T, reduce_op fn (t1 T, t2 T) T) ?T {
|
|||
}
|
||||
|
||||
// accumulates values with providing initial value and applying providing operation to current accumulator value and each elements.
|
||||
// usage: `arrays.fold<string, byte>(['H', 'e', 'l', 'l', 'o'], 0, fn (r int, t string) int { return r + t[0] })` => `149`
|
||||
// Example: arrays.fold<string, byte>(['H', 'e', 'l', 'l', 'o'], 0, fn (r int, t string) int { return r + t[0] }) // => 149
|
||||
pub fn fold<T, R>(list []T, init R, fold_op fn (r R, t T) R) R {
|
||||
mut value := init
|
||||
|
||||
|
@ -239,7 +247,7 @@ pub fn fold<T, R>(list []T, init R, fold_op fn (r R, t T) R) R {
|
|||
}
|
||||
|
||||
// flattens n + 1 dimensional array into n dimensional array
|
||||
// usage: `arrays.flatten<int>([[1, 2, 3], [4, 5]])` => `[1, 2, 3, 4, 5]`
|
||||
// Example: arrays.flatten<int>([[1, 2, 3], [4, 5]]) // => [1, 2, 3, 4, 5]
|
||||
pub fn flatten<T>(list [][]T) []T {
|
||||
// calculate required capacity
|
||||
mut required_size := 0
|
||||
|
@ -263,7 +271,7 @@ pub fn flatten<T>(list [][]T) []T {
|
|||
}
|
||||
|
||||
// grouping list of elements with given key selector.
|
||||
// usage: `arrays.assort<int, string>(['H', 'el', 'lo'], fn (v string) int { return v.len })` => `{1: ['H'], 2: ['el', 'lo']}`
|
||||
// Example: arrays.group_by<int, string>(['H', 'el', 'lo'], fn (v string) int { return v.len }) // => {1: ['H'], 2: ['el', 'lo']}
|
||||
pub fn group_by<K, V>(list []V, grouping_op fn (v V) K) map[K][]V {
|
||||
mut result := map[K][]V{}
|
||||
|
||||
|
@ -281,7 +289,13 @@ pub fn group_by<K, V>(list []V, grouping_op fn (v V) K) map[K][]V {
|
|||
return result
|
||||
}
|
||||
|
||||
// concatenate two arrays
|
||||
// concatenate an array with an arbitrary number of additional values
|
||||
//
|
||||
// NOTE: if you have two arrays, you should simply use the `<<` operator directly
|
||||
// Example: arrays.concat([1, 2, 3], 4, 5, 6) == [1, 2, 3, 4, 5, 6] // => true
|
||||
// Example: arrays.concat([1, 2, 3], ...[4, 5, 6]) == [1, 2, 3, 4, 5, 6] // => true
|
||||
// Example: arr << [4, 5, 6] // does what you need if arr is mutable
|
||||
[deprecated]
|
||||
pub fn concat<T>(a []T, b ...T) []T {
|
||||
mut m := []T{cap: a.len + b.len}
|
||||
|
||||
|
@ -291,7 +305,32 @@ pub fn concat<T>(a []T, b ...T) []T {
|
|||
return m
|
||||
}
|
||||
|
||||
// zip returns a new array by interleaving the source arrays.
|
||||
//
|
||||
// NOTE: The two arrays do not need to be equal sizes
|
||||
// Example: arrays.zip([1, 3, 5, 7], [2, 4, 6, 8, 10]) // => [1, 2, 3, 4, 5, 6, 7, 8, 10]
|
||||
pub fn zip<T>(a []T, b []T) []T {
|
||||
mut m := []T{cap: a.len + b.len}
|
||||
mut i := 0
|
||||
for i < m.cap {
|
||||
// short-circuit the rest of the loop as soon as we can
|
||||
if i >= a.len {
|
||||
m << b[i..]
|
||||
break
|
||||
}
|
||||
if i >= b.len {
|
||||
m << a[i..]
|
||||
break
|
||||
}
|
||||
m << a[i]
|
||||
m << b[i]
|
||||
i++
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// returns the smallest element >= val, requires `arr` to be sorted
|
||||
// Example: arrays.lower_bound([2, 4, 6, 8], 3)? // => 4
|
||||
pub fn lower_bound<T>(arr []T, val T) ?T {
|
||||
if arr.len == 0 {
|
||||
return error('.lower_bound called on an empty array')
|
||||
|
@ -314,6 +353,7 @@ pub fn lower_bound<T>(arr []T, val T) ?T {
|
|||
}
|
||||
|
||||
// returns the largest element <= val, requires `arr` to be sorted
|
||||
// Example: arrays.upper_bound([2, 4, 6, 8], 3)? // => 2
|
||||
pub fn upper_bound<T>(arr []T, val T) ?T {
|
||||
if arr.len == 0 {
|
||||
return error('.upper_bound called on an empty array')
|
||||
|
@ -335,7 +375,10 @@ pub fn upper_bound<T>(arr []T, val T) ?T {
|
|||
}
|
||||
}
|
||||
|
||||
// binary search, requires `arr` to be sorted, returns index
|
||||
// binary search, requires `arr` to be sorted, returns index of found item or error.
|
||||
// Binary searches on sorted lists can be faster than other array searches because at maximum
|
||||
// the algorithm only has to traverse log N elements
|
||||
// Example: arrays.binary_search([1, 2, 3, 4], 4) ? // => 3
|
||||
pub fn binary_search<T>(arr []T, target T) ?int {
|
||||
mut left := 0
|
||||
mut right := arr.len - 1
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
## Description:
|
||||
|
||||
`benchmark` provides an easy way to measure how fast a piece of code is,
|
||||
and produce a readable report about it.
|
||||
`benchmark` provides tools for measuring and reporting on the performance of code.
|
||||
|
||||
## Example usage of this module:
|
||||
## Example 1:
|
||||
|
||||
```v
|
||||
import benchmark
|
||||
|
@ -25,12 +24,13 @@ bmark.stop()
|
|||
println(bmark.total_message('remarks about the benchmark'))
|
||||
```
|
||||
|
||||
benchmark.start() and b.measure() are convenience methods,
|
||||
`.start()` and `.measure()` are convenience methods,
|
||||
intended to be used in combination. Their goal is to make
|
||||
benchmarking of small snippets of code as *short*, easy to
|
||||
write, and then to read and analyze the results, as possible.
|
||||
benchmarking of small snippets of code as _short_, easy to
|
||||
write, and easy to read and analyze as possible.
|
||||
|
||||
## Example 2:
|
||||
|
||||
Example:
|
||||
```v
|
||||
import time
|
||||
import benchmark
|
||||
|
@ -45,6 +45,7 @@ b.measure('code_2')
|
|||
```
|
||||
|
||||
... which will produce on stdout something like this:
|
||||
|
||||
```text
|
||||
SPENT 1500.063 ms in code_1
|
||||
SPENT 500.061 ms in code_2
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
## Description:
|
||||
|
||||
`bitfield` is a module for manipulating arrays of bits, i.e. series of zeroes
|
||||
and ones spread across an array of storage units (unsigned 32-bit integers).
|
||||
`bitfield` is a module for manipulating arrays of bits,
|
||||
i.e. series of zeroes and ones spread across an
|
||||
array of storage units (unsigned 32-bit integers).
|
||||
|
||||
## BitField structure
|
||||
## BitField Structure
|
||||
|
||||
Bit arrays are stored in data structures called 'BitField'. The structure is
|
||||
'opaque', i.e. its internals are not available to the end user. This module
|
||||
|
|
|
@ -4,4 +4,3 @@
|
|||
It implements the builtin V types `array`, `string`, `map`.
|
||||
It also implements builtin functions like `println`, `eprintln`, `malloc`,
|
||||
`panic`, `print_backtrace`.
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ declarative subcommands, each having separate set of options.
|
|||
See also the `flag` module, for a simpler command line option parser,
|
||||
that supports only options.
|
||||
|
||||
Usage example:
|
||||
## Example:
|
||||
|
||||
```v
|
||||
module main
|
||||
|
|
|
@ -3,3 +3,14 @@
|
|||
`clipboard` provides access to the platform's clipboard mechanism.
|
||||
You can use it to read from the system clipboard, and write to it
|
||||
from your applications.
|
||||
|
||||
## Examples:
|
||||
|
||||
```v
|
||||
import clipboard
|
||||
|
||||
fn main() {
|
||||
mut c := clipboard.new()
|
||||
println(c.get_text())
|
||||
}
|
||||
```
|
||||
|
|
|
@ -21,7 +21,7 @@ pub fn (mut cb Clipboard) clear_all() {
|
|||
cb.clear()
|
||||
}
|
||||
|
||||
// destroy destroys the clipboard and free it's resources.
|
||||
// destroy destroys the clipboard and frees its resources.
|
||||
pub fn (mut cb Clipboard) destroy() {
|
||||
cb.free()
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
## Description:
|
||||
|
||||
`compress.zlib` implements zlib compression and decompression of binary data.
|
||||
`compress.zlib` is a module that assists in the compression and
|
||||
decompression of binary data using `zlib` compression
|
||||
|
||||
## Examples:
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ pub const max_size = u64(1 << 31)
|
|||
fn C.tdefl_compress_mem_to_heap(source_buf voidptr, source_buf_len usize, out_len &usize, flags int) voidptr
|
||||
fn C.tinfl_decompress_mem_to_heap(source_buf voidptr, source_buf_len usize, out_len &usize, flags int) voidptr
|
||||
|
||||
// compresses an array of bytes using zlib and returns the compressed bytes in a new array
|
||||
// Example: compressed := zlib.compress(b) ?
|
||||
[manualfree]
|
||||
pub fn compress(data []byte) ?[]byte {
|
||||
if u64(data.len) > zlib.max_size {
|
||||
|
@ -33,6 +35,8 @@ pub fn compress(data []byte) ?[]byte {
|
|||
return copy
|
||||
}
|
||||
|
||||
// decompresses an array of bytes using zlib and returns the decompressed bytes in a new array
|
||||
// Example: decompressed := zlib.decompress(b) ?
|
||||
[manualfree]
|
||||
pub fn decompress(data []byte) ?[]byte {
|
||||
mut out_len := usize(0)
|
||||
|
|
|
@ -1,5 +1,45 @@
|
|||
## Description:
|
||||
|
||||
`crypto` is a namespace for multiple crypto algorithms.
|
||||
`crypto` is a module that exposes cryptographic algorithms to V programs.
|
||||
|
||||
Each submodule implements things differently, so be sure to consider the documentation
|
||||
of the specific algorithm you need, but in general, the method is to create a `cipher`
|
||||
struct using one of the module functions, and then to call the `encrypt` or `decrypt`
|
||||
method on that struct to actually encrypt or decrypt your data.
|
||||
|
||||
This module is a work-in-progress. For example, the AES implementation currently requires you
|
||||
to create a destination buffer of the correct size to receive the decrypted data, and the AesCipher
|
||||
`encrypt` and `decrypt` functions only operate on the first block of the `src`.
|
||||
|
||||
The implementations here are loosely based on [Go's crypto package](https://pkg.go.dev/crypto).
|
||||
|
||||
## Examples:
|
||||
|
||||
```v
|
||||
import crypto.aes
|
||||
import crypto.rand
|
||||
|
||||
fn main() {
|
||||
// remember to save this key somewhere if you ever want to decrypt your data
|
||||
key := rand.read(32) ?
|
||||
println('KEY: $key')
|
||||
|
||||
// this data is one block (16 bytes) big
|
||||
mut data := 'THIS IS THE DATA'.bytes()
|
||||
|
||||
println('generating cipher')
|
||||
cipher := aes.new_cipher(key)
|
||||
|
||||
println('performing encryption')
|
||||
mut encrypted := []byte{len: aes.block_size}
|
||||
cipher.encrypt(mut encrypted, mut data)
|
||||
println(encrypted)
|
||||
|
||||
println('performing decryption')
|
||||
mut decrypted := []byte{len: aes.block_size}
|
||||
cipher.decrypt(mut decrypted, mut encrypted)
|
||||
println(decrypted)
|
||||
|
||||
assert decrypted == data
|
||||
}
|
||||
```
|
||||
|
|
|
@ -13,13 +13,16 @@ pub const (
|
|||
)
|
||||
|
||||
// AesCipher represents an AES encryption using a particular key.
|
||||
// It follows the API of golang's `cipher.Block` and is designed to
|
||||
// handle only one block of data at a time. In most cases, you
|
||||
// probably want to encrypt and decrypt using [[AesCbc](#AesCbc)]
|
||||
struct AesCipher {
|
||||
mut:
|
||||
enc []u32
|
||||
dec []u32
|
||||
}
|
||||
|
||||
// new_cipher creates and returns a new `AesCipher`.
|
||||
// new_cipher creates and returns a new [[AesCipher](#AesCipher)].
|
||||
// The key argument should be the AES key,
|
||||
// either 16, 24, or 32 bytes to select
|
||||
// AES-128, AES-192, or AES-256.
|
||||
|
@ -43,8 +46,10 @@ pub fn (c &AesCipher) block_size() int {
|
|||
return aes.block_size
|
||||
}
|
||||
|
||||
// encrypt encrypts the blocks in `src` to `dst`.
|
||||
// Please note: `dst` and `src` are both mutable for performance reasons.
|
||||
// encrypt encrypts the first block of data in `src` to `dst`.
|
||||
// NOTE: `dst` and `src` are both mutable for performance reasons.
|
||||
// NOTE: `dst` and `src` must both be pre-allocated to the correct length.
|
||||
// NOTE: `dst` and `src` may be the same (overlapping entirely).
|
||||
pub fn (c &AesCipher) encrypt(mut dst []byte, mut src []byte) {
|
||||
if src.len < aes.block_size {
|
||||
panic('crypto.aes: input not full block')
|
||||
|
@ -60,8 +65,10 @@ pub fn (c &AesCipher) encrypt(mut dst []byte, mut src []byte) {
|
|||
encrypt_block_generic(c.enc, mut dst, src)
|
||||
}
|
||||
|
||||
// decrypt decrypts the blocks in `src` to `dst`.
|
||||
// Please note: `dst` and `src` are both mutable for performance reasons.
|
||||
// decrypt decrypts the first block of data in `src` to `dst`.
|
||||
// NOTE: `dst` and `src` are both mutable for performance reasons.
|
||||
// NOTE: `dst` and `src` must both be pre-allocated to the correct length.
|
||||
// NOTE: `dst` and `src` may be the same (overlapping entirely).
|
||||
pub fn (c &AesCipher) decrypt(mut dst []byte, mut src []byte) {
|
||||
if src.len < aes.block_size {
|
||||
panic('crypto.aes: input not full block')
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
Based on Go's crypto packages.
|
||||
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -4,3 +4,54 @@
|
|||
which in turn is a library of "Simple STB-style cross-platform libraries
|
||||
for C and C++, written in C.", that provide access to graphics/audio/input
|
||||
processing.
|
||||
|
||||
Each `.h` file in the sokol source code is well-documented as can be seen here:
|
||||
|
||||
[sokol_audio.h](https://github.com/floooh/sokol/blob/master/sokol_audio.h)
|
||||
|
||||
## Example from `@VROOTDIR/examples/sokol/sounds/simple_sin_tones.v`:
|
||||
|
||||
```v
|
||||
import time
|
||||
import math
|
||||
import sokol.audio
|
||||
|
||||
const (
|
||||
sw = time.new_stopwatch()
|
||||
sw_start_ms = sw.elapsed().milliseconds()
|
||||
)
|
||||
|
||||
[inline]
|
||||
fn sintone(periods int, frame int, num_frames int) f32 {
|
||||
return math.sinf(f32(periods) * (2 * math.pi) * f32(frame) / f32(num_frames))
|
||||
}
|
||||
|
||||
fn my_audio_stream_callback(buffer &f32, num_frames int, num_channels int) {
|
||||
ms := sw.elapsed().milliseconds() - sw_start_ms
|
||||
unsafe {
|
||||
mut soundbuffer := buffer
|
||||
for frame := 0; frame < num_frames; frame++ {
|
||||
for ch := 0; ch < num_channels; ch++ {
|
||||
idx := frame * num_channels + ch
|
||||
if ms < 250 {
|
||||
soundbuffer[idx] = 0.5 * sintone(20, frame, num_frames)
|
||||
} else if ms < 300 {
|
||||
soundbuffer[idx] = 0.5 * sintone(25, frame, num_frames)
|
||||
} else if ms < 1500 {
|
||||
soundbuffer[idx] *= sintone(22, frame, num_frames)
|
||||
} else {
|
||||
soundbuffer[idx] = 0.5 * sintone(25, frame, num_frames)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
audio.setup(
|
||||
stream_cb: my_audio_stream_callback
|
||||
)
|
||||
time.sleep(2000 * time.millisecond)
|
||||
audio.shutdown()
|
||||
}
|
||||
```
|
||||
|
|
|
@ -12,9 +12,37 @@ $if linux {
|
|||
#flag darwin -framework AudioToolbox
|
||||
#flag windows -lole32
|
||||
|
||||
// callback function for `stream_cb` in [[C.saudio_desc](#C.saudio_desc)] when calling [audio.setup()](#setup)
|
||||
//
|
||||
// sokol callback functions run in a separate thread
|
||||
//
|
||||
// This function will be called with a reference to the C buffer and the maximum number of frames and channels
|
||||
// the audio backend is expecting in its buffer.
|
||||
//
|
||||
// Terms:
|
||||
// - *sample* - a 32-bit floating point number from `-1.0` to `+1.0` representing the waveform amplitude at that instant
|
||||
// - *frame* - one sample for each channel at that instant
|
||||
//
|
||||
// To determine the number of samples expected, do `num_frames * num_channels`.
|
||||
// Then, write up to that many `f32` samples into `buffer` using unsafe operations.
|
||||
//
|
||||
// Do not write more data to the buffer than it is requesting, but you may write less. The buffer is initialized with
|
||||
// zeroes, so unwritten data will result in audio silence.
|
||||
// Example: unsafe { C.memcpy(buffer, &samples, samples.len * int(sizeof(f32))) }
|
||||
// Example: unsafe { mut b := buffer; for i, sample in samples { b[i] = sample } }
|
||||
pub type FNStreamingCB = fn (buffer &f32, num_frames int, num_channels int)
|
||||
|
||||
// callback function for `stream_userdata_cb` to use in `C.saudio_desc` when calling [audio.setup()](#setup)
|
||||
//
|
||||
// sokol callback functions run in a separate thread
|
||||
//
|
||||
// This function operates the same way as [[FNStreamingCB](#FNStreamingCB)] but it passes customizable `user_data` to the
|
||||
// callback. This is the method to use if your audio data is stored in a struct or array. Identify the
|
||||
// `user_data` when you call `audio.setup()` and that object will be passed to the callback as the last arg.
|
||||
// Example: mut soundbuffer := []f32
|
||||
// Example: soundbuffer << previously_parsed_wavfile_bytes
|
||||
// Example: audio.setup(stream_userdata_cb: mycallback, user_data: soundbuffer)
|
||||
// Example: fn mycallback(buffer &f32, num_frames int, num_channels int, mut sb []f32) { ... }
|
||||
pub type FnStreamingCBWithUserData = fn (buffer &f32, num_frames int, num_channels int, user_data voidptr)
|
||||
|
||||
pub fn (x FNStreamingCB) str() string {
|
||||
|
@ -25,7 +53,17 @@ pub fn (x FnStreamingCBWithUserData) str() string {
|
|||
return '&FnStreamingCBWithUserData{ ${ptr_str(x)} }'
|
||||
}
|
||||
|
||||
// only one of `stream_cb` or `stream_userdata_cb` should be used
|
||||
//
|
||||
// default values (internal to sokol C library):
|
||||
//
|
||||
// | variable | default | note |
|
||||
// | :----------- | -------: | :--------- |
|
||||
// | sample_rate | 44100 | higher sample rates take more memory but are higher quality |
|
||||
// | num_channels | 1 | for stereo sound, this should be 2 |
|
||||
// | buffer_frames | 2048 | buffer size in frames, larger is more latency, smaller means higher CPU |
|
||||
// | packet_frames | 128 | push model only, number of frames that will be pushed in each packet |
|
||||
// | num_packets | 64 | for push model only, number of packets in the backend ringbuffer |
|
||||
pub struct C.saudio_desc {
|
||||
sample_rate int
|
||||
num_channels int
|
||||
|
@ -84,17 +122,17 @@ pub fn query() C.saudio_desc {
|
|||
return C.saudio_query_desc()
|
||||
}
|
||||
|
||||
// audio.sample_rate - actual sample rate
|
||||
// audio.sample_rate - return the actual sample rate
|
||||
pub fn sample_rate() int {
|
||||
return C.saudio_sample_rate()
|
||||
}
|
||||
|
||||
// audio.buffer_frames - return actual backend buffer size in number of frames
|
||||
// audio.buffer_frames - return the actual backend buffer size in number of frames
|
||||
pub fn buffer_frames() int {
|
||||
return C.saudio_buffer_frames()
|
||||
}
|
||||
|
||||
// audio.channels - actual number of channels
|
||||
// audio.channels - return the actual number of channels
|
||||
pub fn channels() int {
|
||||
return C.saudio_channels()
|
||||
}
|
||||
|
@ -105,7 +143,7 @@ pub fn suspended() bool {
|
|||
return C.saudio_suspended()
|
||||
}
|
||||
|
||||
// audio.expect - get current number of frames to fill packet queue; use in combination with audio.push/2
|
||||
// audio.expect - get current number of frames to fill packet queue; use in combination with audio.push
|
||||
pub fn expect() int {
|
||||
return C.saudio_expect()
|
||||
}
|
||||
|
@ -115,7 +153,8 @@ pub fn push(frames &f32, num_frames int) int {
|
|||
return C.saudio_push(frames, num_frames)
|
||||
}
|
||||
|
||||
//
|
||||
// audio.fclamp - helper function to 'clamp' a number to a certain range
|
||||
// Example: realsample := audio.fclamp(sample, -1.0, 1.0)
|
||||
[inline]
|
||||
pub fn fclamp(x f32, flo f32, fhi f32) f32 {
|
||||
if x > fhi {
|
||||
|
@ -127,6 +166,10 @@ pub fn fclamp(x f32, flo f32, fhi f32) f32 {
|
|||
return x
|
||||
}
|
||||
|
||||
// audio.min - helper function to return the smaller of two numbers
|
||||
//
|
||||
// math.min returns `f32` values, this returns `int` values
|
||||
// Example: smaller := audio.min(1, 5) // smaller == 1
|
||||
pub fn min(x int, y int) int {
|
||||
if x < y {
|
||||
return x
|
||||
|
@ -134,6 +177,10 @@ pub fn min(x int, y int) int {
|
|||
return y
|
||||
}
|
||||
|
||||
// audio.max - helper function to return the larger of two numbers
|
||||
//
|
||||
// math.max returns `f32` values, this returns `int` values
|
||||
// Example: larger := audio.max(1, 5) // larger == 5
|
||||
pub fn max(x int, y int) int {
|
||||
if x < y {
|
||||
return y
|
||||
|
|
Loading…
Reference in New Issue