openal

package
v0.0.0-...-d96453c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 16, 2019 License: BSD-2-Clause Imports: 5 Imported by: 0

Documentation

Overview

C-level binding for OpenAL's "alc" API.

Please consider using the Go-level binding instead.

Note that "alc" introduces the exact same types as "al" but with different names. Check the documentation of openal/al for more information about the mapping to Go types.

XXX: Sadly we have to returns pointers for both Device and Context to avoid problems with implicit assignments in clients. It's sad because it makes the overhead a lot higher, each of those calls triggers an allocation.

Go binding for OpenAL's "al" API.

See http://connect.creativelabs.com/openal/Documentation/OpenAL%201.1%20Specification.htm for details about OpenAL not described here.

OpenAL types are (in principle) mapped to Go types as follows:

ALboolean	bool	(al.h says char, but Go's bool should be compatible)
ALchar		uint8	(although al.h suggests int8, Go's uint8 (aka byte) seems better)
ALbyte		int8	(al.h says char, implying that char is signed)
ALubyte		uint8	(al.h says unsigned char)
ALshort		int16
ALushort	uint16
ALint		int32
ALuint		uint32
ALsizei		int32	(although that's strange, it's what OpenAL wants)
ALenum		int32	(although that's strange, it's what OpenAL wants)
ALfloat		float32
ALdouble	float64
ALvoid		not applicable (but see below)

We also stick to these (not mentioned explicitly in OpenAL):

ALvoid*		unsafe.Pointer (but never exported)
ALchar*		string

Finally, in places where OpenAL expects pointers to C-style arrays, we use Go slices if appropriate:

ALboolean*	[]bool
ALvoid*		[]byte (see Buffer.SetData() for example)
ALint*		[]int32
ALuint*		[]uint32 []Source []Buffer
ALfloat*	[]float32
ALdouble*	[]float64

Overall, the correspondence of types hopefully feels natural enough. Note that many of these types do not actually occur in the API.

The names of OpenAL constants follow the established Go conventions: instead of AL_FORMAT_MONO16 we use FormatMono16 for example.

Conversion to Go's camel case notation does however lead to name clashes between constants and functions. For example, AL_DISTANCE_MODEL becomes DistanceModel which collides with the OpenAL function of the same name used to set the current distance model. We have to rename either the constant or the function, and since the function name seems to be at fault (it's a setter but doesn't make that obvious), we rename the function.

In fact, we renamed plenty of functions, not just the ones where collisions with constants were the driving force. For example, instead of the Sourcef/GetSourcef abomination, we use Getf/Setf methods on a Source type. Everything should still be easily recognizable for OpenAL hackers, but this structure is a lot more sensible (and reveals that the OpenAL API is actually not such a bad design).

There are a few cases where constants would collide with the names of types we introduced here. Since the types serve a much more important function, we renamed the constants in those cases. For example AL_BUFFER would collide with the type Buffer so it's name is now Buffer_ instead. Not pretty, but in many cases you don't need the constants anyway as the functionality they represent is probably available through one of the convenience functions we introduced as well. For example consider the task of attaching a buffer to a source. In C, you'd say alSourcei(sid, AL_BUFFER, bid). In Go, you can say sid.Seti(Buffer_, bid) as well, but you probably want to say sid.SetBuffer(bid) instead.

TODO: Decide on the final API design; the current state has only specialized methods, none of the generic ones anymore; it exposes everything (except stuff we can't do) but I am not sure whether this is the right API for the level we operate on. Not yet anyway. Anyone?

Index

Constants

View Source
const (
	Frequency     = 0x1007 // int Hz
	Refresh       = 0x1008 // int Hz
	Sync          = 0x1009 // bool
	MonoSources   = 0x1010 // int
	StereoSources = 0x1011 // int
)
View Source
const (
	DefaultDeviceSpecifier = 0x1004
	DeviceSpecifier        = 0x1005
	Extensions             = 0x1006
	AllDevicesSpecifier    = 0x1013
)

The Specifier string for default device?

View Source
const (
	MajorVersion = 0x1000
	MinorVersion = 0x1001
)

?

View Source
const (
	AttributesSize = 0x1002
	AllAttributes  = 0x1003
)

?

View Source
const (
	CaptureDeviceSpecifier        = 0x310
	CaptureDefaultDeviceSpecifier = 0x311
	CaptureSamples                = 0x312
)

Capture extension

View Source
const (
	AlPosition = 0x1004
	AlVelocity = 0x1006
	AlGain     = 0x100A
)

Shared Source/Listener properties.

View Source
const (
	InverseDistance         = 0xD001
	InverseDistanceClamped  = 0xD002
	LinearDistance          = 0xD003
	LinearDistanceClamped   = 0xD004
	ExponentDistance        = 0xD005
	ExponentDistanceClamped = 0xD006
)

Distance models for SetDistanceModel() and GetDistanceModel().

View Source
const (
	Static       = 0x1028
	Streaming    = 0x1029
	Undetermined = 0x1030
)

Results from Source.Type() query.

View Source
const (
	AlSourceRelative    = 0x202
	AlConeInnerAngle    = 0x1001
	AlConeOuterAngle    = 0x1002
	AlPitch             = 0x1003
	AlDirection         = 0x1005
	AlLooping           = 0x1007
	AlBuffer            = 0x1009
	AlMinGain           = 0x100D
	AlMaxGain           = 0x100E
	AlReferenceDistance = 0x1020
	AlRolloffFactor     = 0x1021
	AlConeOuterGain     = 0x1022
	AlMaxDistance       = 0x1023
	AlSecOffset         = 0x1024
	AlSampleOffset      = 0x1025
	AlByteOffset        = 0x1026
)

TODO: Source properties. Regardless of what your al.h header may claim, Pitch only applies to Sources, not to Listeners. And I got that from Chris Robinson himself.

View Source
const (
	AlSourceState      = 0x1010
	AlBuffersQueued    = 0x1015
	AlBuffersProcessed = 0x1016
	AlSourceType       = 0x1027
)

Source queries. TODO: SourceType isn't documented as a query in the al.h header, but it is documented that way in the OpenAL 1.1 specification.

View Source
const (
	AlOrientation = 0x100F
)

Listener properties.

View Source
const (
	None = 0
)

General purpose constants. None can be used with SetDistanceModel() to disable distance attenuation. None can be used with Source.SetBuffer() to clear a Source of buffers.

Variables

View Source
var (
	ErrInvalidName      = errors.New("openal: invalid name")
	ErrInvalidEnum      = errors.New("openal: invalid enum")
	ErrInvalidValue     = errors.New("openal: invalid value")
	ErrInvalidOperation = errors.New("openal: invalid operation")

	ErrInvalidContext = errors.New("openal: invalid context")
	ErrInvalidDevice  = errors.New("openal: invalid device")
	ErrOutOfMemory    = errors.New("openal: out of memory")
)

Functions

func Err

func Err() error

Err() returns the most recent error generated in the AL state machine.

func GetDistanceModel

func GetDistanceModel() int32

Convenience function, see GetInteger().

func GetDopplerFactor

func GetDopplerFactor() float32

Convenience function, see GetFloat().

func GetDopplerVelocity

func GetDopplerVelocity() float32

Convenience function, see GetFloat().

func GetExtensions

func GetExtensions() string

Convenience function, see GetString().

func GetExtensionsSlice

func GetExtensionsSlice() []string

func GetRenderer

func GetRenderer() string

Convenience function, see GetString().

func GetSpeedOfSound

func GetSpeedOfSound() float32

Convenience function, see GetFloat().

func GetString

func GetString(param int32) string

func GetStrings

func GetStrings(param int32) []string

warning: this function does not free internal pointers warning: memory leak

func GetVendor

func GetVendor() string

Convenience function, see GetString().

func GetVersion

func GetVersion() string

Convenience function, see GetString().

func IsExtensionPresent

func IsExtensionPresent(ext string) bool

func SetDistanceModel

func SetDistanceModel(model int32)

SetDistanceModel() changes the current distance model. Pass "None" to disable distance attenuation. Renamed, was DistanceModel.

func SetDopplerFactor

func SetDopplerFactor(value float32)

Renamed, was DopplerFactor.

func SetDopplerVelocity

func SetDopplerVelocity(value float32)

Renamed, was DopplerVelocity.

func SetSpeedOfSound

func SetSpeedOfSound(value float32)

Renamed, was SpeedOfSound.

Types

type Buffer

type Buffer uint32

Buffers are storage space for sample data.

func NewBuffer

func NewBuffer() Buffer

NewBuffer() creates a single buffer. Convenience function, see NewBuffers().

func (Buffer) Delete

func (self Buffer) Delete()

Delete() deletes a single buffer. Convenience function, see DeleteBuffers().

func (Buffer) GetBits

func (self Buffer) GetBits() uint32

GetBits() returns the resolution, either 8 or 16 bits, of the buffer's sample data. Convenience method.

func (Buffer) GetChannels

func (self Buffer) GetChannels() uint32

GetChannels() returns the number of channels, either 1 or 2, of the buffer's sample data. Convenience method.

func (Buffer) GetFrequency

func (self Buffer) GetFrequency() uint32

GetFrequency() returns the frequency, in Hz, of the buffer's sample data. Convenience method.

func (Buffer) GetSize

func (self Buffer) GetSize() uint32

GetSize() returns the size, in bytes, of the buffer's sample data. Convenience method.

func (Buffer) SetData

func (self Buffer) SetData(format Format, data []byte, frequency int32)

SetData() specifies the sample data the buffer should use. For FormatMono16 and FormatStereo8 the data slice must be a multiple of two bytes long; for FormatStereo16 the data slice must be a multiple of four bytes long. The frequency is given in Hz. Renamed, was BufferData.

func (Buffer) SetDataInt16

func (self Buffer) SetDataInt16(format Format, data []int16, frequency int32)

func (Buffer) SetDataMono16

func (self Buffer) SetDataMono16(data []int16, frequency int32)

func (Buffer) SetDataMono8

func (self Buffer) SetDataMono8(data []byte, frequency int32)

func (Buffer) SetDataStereo16

func (self Buffer) SetDataStereo16(data [][2]int16, frequency int32)

func (Buffer) SetDataStereo8

func (self Buffer) SetDataStereo8(data [][2]byte, frequency int32)

type Buffers

type Buffers []Buffer

func NewBuffers

func NewBuffers(n int) (buffers Buffers)

NewBuffers() creates n fresh buffers. Renamed, was GenBuffers.

func (Buffers) Delete

func (self Buffers) Delete()

Delete() deletes the given buffers.

type CaptureDevice

type CaptureDevice struct {
	Device
	// contains filtered or unexported fields
}

func CaptureOpenDevice

func CaptureOpenDevice(name string, freq uint32, format Format, size uint32) *CaptureDevice

func (*CaptureDevice) CaptureCloseDevice

func (self *CaptureDevice) CaptureCloseDevice() bool

func (*CaptureDevice) CaptureMono16To

func (self *CaptureDevice) CaptureMono16To(data []int16)

func (*CaptureDevice) CaptureMono8To

func (self *CaptureDevice) CaptureMono8To(data []byte)

func (*CaptureDevice) CaptureSamples

func (self *CaptureDevice) CaptureSamples(size uint32) (data []byte)

func (*CaptureDevice) CaptureSamplesInt16

func (self *CaptureDevice) CaptureSamplesInt16(size uint32) (data []int16)

func (*CaptureDevice) CaptureStart

func (self *CaptureDevice) CaptureStart()

func (*CaptureDevice) CaptureStereo16To

func (self *CaptureDevice) CaptureStereo16To(data [][2]int16)

func (*CaptureDevice) CaptureStereo8To

func (self *CaptureDevice) CaptureStereo8To(data [][2]byte)

func (*CaptureDevice) CaptureStop

func (self *CaptureDevice) CaptureStop()

func (*CaptureDevice) CaptureTo

func (self *CaptureDevice) CaptureTo(data []byte)

func (*CaptureDevice) CaptureToInt16

func (self *CaptureDevice) CaptureToInt16(data []int16)

func (*CaptureDevice) CapturedSamples

func (self *CaptureDevice) CapturedSamples() (size uint32)

func (*CaptureDevice) CloseDevice

func (self *CaptureDevice) CloseDevice() bool

XXX: Override Device.CloseDevice to make sure the correct C function is called even if someone decides to use this behind an interface.

type Context

type Context struct {
	// contains filtered or unexported fields
}

Context encapsulates the state of a given instance of the OpenAL state machine. Only one context can be active in a given process.

var NullContext Context

A context that doesn't exist, useful for certain context operations (see OpenAL documentation for details).

func CurrentContext

func CurrentContext() *Context

Renamed, was GetCurrentContext.

func (*Context) Activate

func (self *Context) Activate() bool

Renamed, was MakeContextCurrent.

func (*Context) Destroy

func (self *Context) Destroy()

Renamed, was DestroyContext.

func (*Context) GetDevice

func (self *Context) GetDevice() *Device

Renamed, was GetContextsDevice.

func (*Context) Process

func (self *Context) Process()

Renamed, was ProcessContext.

func (*Context) Suspend

func (self *Context) Suspend()

Renamed, was SuspendContext.

type Device

type Device struct {
	// contains filtered or unexported fields
}

func OpenDevice

func OpenDevice(name string) *Device

func (*Device) CloseDevice

func (self *Device) CloseDevice() bool

func (*Device) CreateContext

func (self *Device) CreateContext() *Context

func (*Device) Err

func (self *Device) Err() error

Err() returns the most recent error generated in the AL state machine.

func (*Device) GetInteger

func (self *Device) GetInteger(param uint32) int32

func (*Device) GetIntegerv

func (self *Device) GetIntegerv(param uint32, size uint32) (result []int32)

type ErrorCode

type ErrorCode uint32

func (ErrorCode) Error

func (e ErrorCode) Error() string

type Format

type Format uint32
const (
	FormatMono8    Format = 0x1100
	FormatMono16   Format = 0x1101
	FormatStereo8  Format = 0x1102
	FormatStereo16 Format = 0x1103
)

Format of sound samples passed to Buffer.SetData().

func (Format) SampleSize

func (f Format) SampleSize() int

type Listener

type Listener struct{}

Listener represents the singleton receiver of sound in 3d space.

We "fake" this type so we can provide OpenAL listener calls as methods. This is convenient and makes all those calls consistent with the way they work for Source and Buffer. You can't make new listeners, there's only one!

func (Listener) Get3f

func (self Listener) Get3f(param int32) (v1, v2, v3 float32)

Renamed, was GetListener3f.

func (Listener) Get3i

func (self Listener) Get3i(param int32) (v1, v2, v3 int32)

Renamed, was GetListener3i.

func (Listener) GetGain

func (self Listener) GetGain() (gain float32)

Convenience method, see Listener.Getf().

func (Listener) GetOrientation

func (self Listener) GetOrientation(resultAt, resultUp *Vector)

Convenience method, see Listener.Getfv().

func (Listener) GetPosition

func (self Listener) GetPosition(result *Vector)

Convenience method, see Listener.Getfv().

func (Listener) GetVelocity

func (self Listener) GetVelocity(result *Vector)

Convenience method, see Listener.Getfv().

func (Listener) Getf

func (self Listener) Getf(param int32) float32

Renamed, was GetListenerf.

func (Listener) Getfv

func (self Listener) Getfv(param int32, values []float32)

Renamed, was GetListenerfv.

func (Listener) Geti

func (self Listener) Geti(param int32) int32

Renamed, was GetListeneri.

func (Listener) Getiv

func (self Listener) Getiv(param int32, values []int32)

Renamed, was GetListeneriv.

func (Listener) Set3f

func (self Listener) Set3f(param int32, value1, value2, value3 float32)

Renamed, was Listener3f.

func (Listener) Set3i

func (self Listener) Set3i(param int32, value1, value2, value3 int32)

Renamed, was Listener3i.

func (Listener) SetGain

func (self Listener) SetGain(gain float32)

Convenience method, see Listener.Setf().

func (Listener) SetOrientation

func (self Listener) SetOrientation(at *Vector, up *Vector)

Convenience method, see Listener.Setfv().

func (Listener) SetPosition

func (self Listener) SetPosition(vector *Vector)

Convenience method, see Listener.Setfv().

func (Listener) SetVelocity

func (self Listener) SetVelocity(vector *Vector)

Convenience method, see Listener.Setfv().

func (Listener) Setf

func (self Listener) Setf(param int32, value float32)

Renamed, was Listenerf.

func (Listener) Setfv

func (self Listener) Setfv(param int32, values []float32)

Renamed, was Listenerfv.

func (Listener) Seti

func (self Listener) Seti(param int32, value int32)

Renamed, was Listeneri.

func (Listener) Setiv

func (self Listener) Setiv(param int32, values []int32)

Renamed, was Listeneriv.

type Source

type Source uint32

Sources represent sound emitters in 3d space.

func NewSource

func NewSource() Source

NewSource() creates a single source. Convenience function, see NewSources().

func (Source) BuffersProcessed

func (self Source) BuffersProcessed() int32

Convenience method, see Source.Geti().

func (Source) BuffersQueued

func (self Source) BuffersQueued() int32

Convenience method, see Source.Geti().

func (Source) Delete

func (self Source) Delete()

Delete deletes the source. Convenience function, see DeleteSources().

func (Source) Get3f

func (self Source) Get3f(param int32) (v1, v2, v3 float32)

Renamed, was GetSource3f.

func (Source) Get3i

func (self Source) Get3i(param int32) (v1, v2, v3 int32)

Renamed, was GetSource3i.

func (Source) GetBuffer

func (self Source) GetBuffer() (buffer Buffer)

Convenience method, see Source.Geti().

func (Source) GetDirection

func (self Source) GetDirection(result *Vector)

Convenience method, see Source.Getfv().

func (Source) GetGain

func (self Source) GetGain() (gain float32)

Convenience method, see Source.Getf().

func (Source) GetInnerAngle

func (self Source) GetInnerAngle() float32

Convenience method, see Source.Getf().

func (Source) GetLooping

func (self Source) GetLooping() bool

Convenience method, see Source.Geti().

func (Source) GetMaxDistance

func (self Source) GetMaxDistance() (distance float32)

Convenience method, see Source.Getf().

func (Source) GetMaxGain

func (self Source) GetMaxGain() (gain float32)

Convenience method, see Source.Getf().

func (Source) GetMinGain

func (self Source) GetMinGain() (gain float32)

Convenience method, see Source.Getf().

func (Source) GetOffsetBytes

func (self Source) GetOffsetBytes() int32

Convenience method, see Source.Geti().

func (Source) GetOffsetSamples

func (self Source) GetOffsetSamples() int32

Convenience method, see Source.Geti().

func (Source) GetOffsetSeconds

func (self Source) GetOffsetSeconds() float32

Convenience method, see Source.Getf().

func (Source) GetOuterAngle

func (self Source) GetOuterAngle() float32

Convenience method, see Source.Getf().

func (Source) GetOuterGain

func (self Source) GetOuterGain() float32

Convenience method, see Source.Getf().

func (Source) GetPitch

func (self Source) GetPitch() float32

Convenience method, see Source.Getf().

func (Source) GetPosition

func (self Source) GetPosition(result *Vector)

Convenience method, see Source.Getfv().

func (Source) GetReferenceDistance

func (self Source) GetReferenceDistance() (distance float32)

Convenience method, see Source.Getf().

func (Source) GetRolloffFactor

func (self Source) GetRolloffFactor() (gain float32)

Convenience method, see Source.Getf().

func (Source) GetSourceRelative

func (self Source) GetSourceRelative() bool

Convenience method, see Source.Geti().

func (Source) GetVelocity

func (self Source) GetVelocity(result *Vector)

Convenience method, see Source.Getfv().

func (Source) Getf

func (self Source) Getf(param int32) float32

Renamed, was GetSourcef.

func (Source) Getfv

func (self Source) Getfv(param int32, values []float32)

Renamed, was GetSourcefv.

func (Source) Geti

func (self Source) Geti(param int32) int32

Renamed, was GetSourcei.

func (Source) Getiv

func (self Source) Getiv(param int32, values []int32)

Renamed, was GetSourceiv.

func (Source) Pause

func (self Source) Pause()

Renamed, was SourcePause.

func (Source) Play

func (self Source) Play()

Renamed, was SourcePlay.

func (Source) QueueBuffer

func (self Source) QueueBuffer(buffer Buffer)

Convenience method, see Source.QueueBuffers().

func (Source) QueueBuffers

func (self Source) QueueBuffers(buffers Buffers)

Renamed, was SourceQueueBuffers.

func (Source) Rewind

func (self Source) Rewind()

Renamed, was SourceRewind.

func (Source) Set3f

func (self Source) Set3f(param int32, value1, value2, value3 float32)

Renamed, was Source3f.

func (Source) Set3i

func (self Source) Set3i(param int32, value1, value2, value3 int32)

Renamed, was Source3i.

func (Source) SetBuffer

func (self Source) SetBuffer(buffer Buffer)

Convenience method, see Source.Geti().

func (Source) SetDirection

func (self Source) SetDirection(vector *Vector)

Convenience method, see Source.Setfv().

func (Source) SetGain

func (self Source) SetGain(gain float32)

Convenience method, see Source.Setf().

func (Source) SetInnerAngle

func (self Source) SetInnerAngle(offset float32)

Convenience method, see Source.Setf().

func (Source) SetLooping

func (self Source) SetLooping(yes bool)

Convenience method, see Source.Seti().

func (Source) SetMaxDistance

func (self Source) SetMaxDistance(distance float32)

Convenience method, see Source.Setf().

func (Source) SetMaxGain

func (self Source) SetMaxGain(gain float32)

Convenience method, see Source.Setf().

func (Source) SetMinGain

func (self Source) SetMinGain(gain float32)

Convenience method, see Source.Setf().

func (Source) SetOffsetBytes

func (self Source) SetOffsetBytes(offset int32)

Convenience method, see Source.Seti().

func (Source) SetOffsetSamples

func (self Source) SetOffsetSamples(offset int32)

Convenience method, see Source.Seti().

func (Source) SetOffsetSeconds

func (self Source) SetOffsetSeconds(offset float32)

Convenience method, see Source.Setf().

func (Source) SetOuterAngle

func (self Source) SetOuterAngle(offset float32)

Convenience method, see Source.Setf().

func (Source) SetOuterGain

func (self Source) SetOuterGain(offset float32)

Convenience method, see Source.Setf().

func (Source) SetPitch

func (self Source) SetPitch(pitch float32)

Convenience method, see Source.Setf().

func (Source) SetPosition

func (self Source) SetPosition(vector *Vector)

Convenience method, see Source.Setfv().

func (Source) SetReferenceDistance

func (self Source) SetReferenceDistance(distance float32)

Convenience method, see Source.Setf().

func (Source) SetRolloffFactor

func (self Source) SetRolloffFactor(gain float32)

Convenience method, see Source.Setf().

func (Source) SetSourceRelative

func (self Source) SetSourceRelative(yes bool)

Convenience method, see Source.Seti().

func (Source) SetVelocity

func (self Source) SetVelocity(vector *Vector)

Convenience method, see Source.Setfv().

func (Source) Setf

func (self Source) Setf(param int32, value float32)

Renamed, was Sourcef.

func (Source) Setfv

func (self Source) Setfv(param int32, values []float32)

Renamed, was Sourcefv.

func (Source) Seti

func (self Source) Seti(param int32, value int32)

Renamed, was Sourcei.

func (Source) Setiv

func (self Source) Setiv(param int32, values []int32)

Renamed, was Sourceiv.

func (Source) State

func (self Source) State() State

Convenience method, see Source.Geti().

func (Source) Stop

func (self Source) Stop()

Renamed, was SourceStop.

func (Source) Type

func (self Source) Type() int32

Convenience method, see Source.Geti().

func (Source) UnqueueBuffer

func (self Source) UnqueueBuffer() Buffer

Convenience method, see Source.QueueBuffers().

func (Source) UnqueueBuffers

func (self Source) UnqueueBuffers(buffers Buffers)

Renamed, was SourceUnqueueBuffers.

type Sources

type Sources []Source

func NewSources

func NewSources(n int) (sources Sources)

NewSources() creates n sources. Renamed, was GenSources.

func (Sources) Delete

func (self Sources) Delete()

Delete deletes the sources.

func (Sources) Pause

func (self Sources) Pause()

Renamed, was SourcePausev.

func (Sources) Play

func (self Sources) Play()

Renamed, was SourcePlayv.

func (Sources) Rewind

func (self Sources) Rewind()

Renamed, was SourceRewindv.

func (Sources) Stop

func (self Sources) Stop()

Renamed, was SourceStopv.

type State

type State int32
const (
	Initial State = 0x1011
	Playing State = 0x1012
	Paused  State = 0x1013
	Stopped State = 0x1014
)

Results from Source.State() query.

func (State) String

func (s State) String() string

type Vector

type Vector [3]float32

Convenience Interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL