187ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
287ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao * Use of this source code is governed by a BSD-style license that can be
387ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao * found in the LICENSE file.
487ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao */
587ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao
687ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao#include <stdlib.h>
7c677a0b94719d82e9fab2bb7559e9818ef60d648Dylan Reid#include <sys/param.h>
887ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao
987ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao#include "cras_audio_area.h"
1087ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao#include "cras_audio_format.h"
11501ff6948b4a88694c705964dc6fde86cb7340b2Dylan Reid#include "cras_mix.h"
1287ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao
1387ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chaostruct cras_audio_area *cras_audio_area_create(int num_channels)
1487ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao{
1587ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	struct cras_audio_area *area;
1687ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	size_t sz;
1787ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao
1887ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	sz = sizeof(*area) + num_channels * sizeof(struct cras_channel_area);
1987ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	area = calloc(1, sz);
2087ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	area->num_channels = num_channels;
2187ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao
2287ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	return area;
2387ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao}
2487ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao
25bc0496defda90cdc6d4427d43bcbb04338400a0eDylan Reidunsigned int cras_audio_area_copy(const struct cras_audio_area *dst,
26bc0496defda90cdc6d4427d43bcbb04338400a0eDylan Reid				  unsigned int dst_offset,
278cd4a917e6cef477799245a4e81fe3709ceff6c9Dylan Reid				  const struct cras_audio_format *dst_fmt,
28bc0496defda90cdc6d4427d43bcbb04338400a0eDylan Reid				  const struct cras_audio_area *src,
29bc0496defda90cdc6d4427d43bcbb04338400a0eDylan Reid				  unsigned int src_offset,
30a7031f6452138ef6edd64f5ef75002299e2dd32aCheng-Yi Chiang				  float software_gain_scaler)
311c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao{
321c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao	unsigned int src_idx, dst_idx;
33c677a0b94719d82e9fab2bb7559e9818ef60d648Dylan Reid	unsigned int ncopy;
341c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao	uint8_t *schan, *dchan;
351c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao
36bc0496defda90cdc6d4427d43bcbb04338400a0eDylan Reid	ncopy = MIN(src->frames - src_offset, dst->frames - dst_offset);
37c677a0b94719d82e9fab2bb7559e9818ef60d648Dylan Reid
381c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao	/* TODO(dgreid) - this replaces a memcpy, it needs to be way faster. */
391c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao	for (src_idx = 0; src_idx < src->num_channels; src_idx++) {
401c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao
411c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao		for (dst_idx = 0; dst_idx < dst->num_channels; dst_idx++) {
421c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao			if (!(src->channels[src_idx].ch_set &
431c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao			      dst->channels[dst_idx].ch_set))
441c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao				continue;
451c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao
46bc0496defda90cdc6d4427d43bcbb04338400a0eDylan Reid			schan = src->channels[src_idx].buf +
477c1e82fbb2b8f139a096e7d4103bfa501b106c71Dylan Reid				src_offset * src->channels[src_idx].step_bytes;
481c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao			dchan = dst->channels[dst_idx].buf +
491c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao				dst_offset * dst->channels[dst_idx].step_bytes;
501c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao
51dcbdb01f1bdafd5a60e23432744cc40fff4eef44Cheng-Yi Chiang			cras_mix_add_scale_stride(dst_fmt->format, dchan, schan,
52501ff6948b4a88694c705964dc6fde86cb7340b2Dylan Reid					    ncopy,
53501ff6948b4a88694c705964dc6fde86cb7340b2Dylan Reid					    dst->channels[dst_idx].step_bytes,
54dcbdb01f1bdafd5a60e23432744cc40fff4eef44Cheng-Yi Chiang					    src->channels[src_idx].step_bytes,
55a7031f6452138ef6edd64f5ef75002299e2dd32aCheng-Yi Chiang					    software_gain_scaler);
561c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao		}
571c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao	}
58bc0496defda90cdc6d4427d43bcbb04338400a0eDylan Reid
59bc0496defda90cdc6d4427d43bcbb04338400a0eDylan Reid	return ncopy;
601c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao}
611c84d884fdfcd82c85cc6ab07a4b208b2d34d887Hsin-Yu Chao
6287ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chaovoid cras_audio_area_destroy(struct cras_audio_area *area)
6387ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao{
6487ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	free(area);
6587ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao}
6687ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao
6787ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chaovoid cras_audio_area_config_channels(struct cras_audio_area *area,
6887ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao				     const struct cras_audio_format *fmt)
6987ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao{
7087ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	unsigned int i, ch;
7187ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao
7287ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	/* For mono, config the channel type to match both front
7387ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	 * left and front right.
7487ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	 * TODO(hychao): add more mapping when we have like {FL, FC}
7587ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	 * for mono + kb mic.
7687ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	 */
7787ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	if ((fmt->num_channels == 1) &&
78b2540cbe5809a7714c3fafc88fe41dafe1b6135aHsin-Yu Chao	    ((fmt->channel_layout[CRAS_CH_FC] == 0) ||
79b2540cbe5809a7714c3fafc88fe41dafe1b6135aHsin-Yu Chao	     (fmt->channel_layout[CRAS_CH_FL] == 0))) {
80b2540cbe5809a7714c3fafc88fe41dafe1b6135aHsin-Yu Chao		channel_area_set_channel(area->channels, CRAS_CH_FL);
8187ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao		channel_area_set_channel(area->channels, CRAS_CH_FR);
82b2540cbe5809a7714c3fafc88fe41dafe1b6135aHsin-Yu Chao		return;
83b2540cbe5809a7714c3fafc88fe41dafe1b6135aHsin-Yu Chao	}
84b2540cbe5809a7714c3fafc88fe41dafe1b6135aHsin-Yu Chao
85b2540cbe5809a7714c3fafc88fe41dafe1b6135aHsin-Yu Chao	for (i = 0; i < fmt->num_channels; i++) {
86b2540cbe5809a7714c3fafc88fe41dafe1b6135aHsin-Yu Chao		area->channels[i].ch_set = 0;
87b2540cbe5809a7714c3fafc88fe41dafe1b6135aHsin-Yu Chao		for (ch = 0; ch < CRAS_CH_MAX; ch++)
88b2540cbe5809a7714c3fafc88fe41dafe1b6135aHsin-Yu Chao			if (fmt->channel_layout[ch] == i)
89b2540cbe5809a7714c3fafc88fe41dafe1b6135aHsin-Yu Chao				channel_area_set_channel(&area->channels[i], ch);
90b2540cbe5809a7714c3fafc88fe41dafe1b6135aHsin-Yu Chao	}
91b2540cbe5809a7714c3fafc88fe41dafe1b6135aHsin-Yu Chao
9287ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao}
9387ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao
9487ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chaovoid cras_audio_area_config_buf_pointers(struct cras_audio_area *area,
9587ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao					 const struct cras_audio_format *fmt,
9687ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao					 uint8_t *base_buffer)
9787ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao{
9887ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	int i;
9987ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	const int sample_size = snd_pcm_format_physical_width(fmt->format) / 8;
10087ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao
10187ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	/* TODO(dgreid) - assuming interleaved audio here for now. */
10287ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	for (i = 0 ; i < area->num_channels; i++) {
10387ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao		area->channels[i].step_bytes = cras_get_format_bytes(fmt);
10487ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao		area->channels[i].buf = base_buffer + i * sample_size;
10587ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao	}
10687ee399d94dc527c4ebe3e4da0febe1490f1f5fbHsin-Yu Chao}
107