summaryrefslogtreecommitdiff
path: root/apps/plugins/lib/grey_scroll.c
blob: 56021d149ae916d6d5974b49da8958658aa5c1d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* Copyright (C) Jean-Marc Valin */
/**
   @file speex_echo.h
   @brief Echo cancellation
*/
/*
   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are
   met:

   1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

   2. 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.

   3. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/

#ifndef SPEEX_ECHO_H
#define SPEEX_ECHO_H
/** @defgroup SpeexEchoState SpeexEchoState: Acoustic echo canceller
 *  This is the acoustic echo canceller module.
 *  @{
 */
#include "speex_types.h"

#ifdef __cplusplus
extern "C" {
#endif

/** Obtain frame size used by the AEC */
#define SPEEX_ECHO_GET_FRAME_SIZE 3

/** Set sampling rate */
#define SPEEX_ECHO_SET_SAMPLING_RATE 24
/** Get sampling rate */
#define SPEEX_ECHO_GET_SAMPLING_RATE 25

/** Internal echo canceller state. Should never be accessed directly. */
struct SpeexEchoState_;

/** @class SpeexEchoState
 * This holds the state of the echo canceller. You need one per channel. 
*/

/** Internal echo canceller state. Should never be accessed directly. */
typedef struct SpeexEchoState_ SpeexEchoState;

/** Creates a new echo canceller state
 * @param frame_size Number of samples to process at one time (should correspond to 10-20 ms)
 * @param filter_length Number of samples of echo to cancel (should generally correspond to 100-500 ms)
 * @return Newly-created echo canceller state
 */
SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length);

/** Destroys an echo canceller state 
 * @param st Echo canceller state
*/
void speex_echo_state_destroy(SpeexEchoState *st);

/** Performs echo cancellation a frame, based on the audio sent to the speaker (no delay is added
 * to playback in this form)
 *
 * @param st Echo canceller state
 * @param rec Signal from the microphone (near end + far end echo)
 * @param play Signal played to the speaker (received from far end)
 * @param out Returns near-end signal with echo removed
 */
void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *rec, const spx_int16_t *play, spx_int16_t *out);

/** Performs echo cancellation a frame (deprecated) */
void speex_echo_cancel(SpeexEchoState *st, const/***************************************************************************
*             __________               __   ___.
*   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
*   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
*   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
*   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
*                     \/            \/     \/    \/            \/
* $Id$
*
* New greyscale framework
* Scrolling routines
*
* This is a generic framework to display 129 shades of grey on low-depth
* bitmap LCDs (Archos b&w, Iriver & Ipod 4-grey) within plugins.
*
* Copyright (C) 2008 Jens Arnold
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/

#include "plugin.h"
#include "grey.h"

/*** Scrolling ***/

/* Scroll left */
void grey_scroll_left(int count)
{
    unsigned char *data, *data_end;
    int length, blank;

    if ((unsigned)count >= (unsigned)_grey_info.width)
        return;

    data = _grey_info.buffer;
    data_end = data + _GREY_MULUQ(_grey_info.width, _grey_info.height);
    length = _grey_info.width - count;
    blank = (_grey_info.drawmode & DRMODE_INVERSEVID) ?
             _grey_info.fg_brightness : _grey_info.bg_brightness;

    do
    {
        _grey_info.rb->memmove(data, data + count, length);
        data += length;
        _grey_info.rb->memset(data, blank, count);
        data += count;
    }
    while (data < data_end);
}

/* Scroll right */
void grey_scroll_right(int count)
{
    unsigned char *data, *data_end;
    int length, blank;

    if ((unsigned)count >= (unsigned)_grey_info.width)
        return;

    data = _grey_info.buffer;
    data_end = data + _GREY_MULUQ(_grey_info.width, _grey_info.height);
    length = _grey_info.width - count;
    blank = (_grey_info.drawmode & DRMODE_INVERSEVID) ?
             _grey_info.fg_brightness : _grey_info.bg_brightness;

    do
    {
        _grey_info.rb->memmove(data + count, data, length);
        _grey_info.rb->memset(data, blank, count);
        data += _grey_info.width;
    }
    while (data < data_end);
}

/* Scroll up */
void grey_scroll_up(int count)
{
    long shift, length;
    int blank;

    if ((unsigned)count >= (unsigned)_grey_info.height)
        return;

    shift = _GREY_MULUQ(_grey_info.width, count);
    length = _GREY_MULUQ(_grey_info.width, _grey_info.height - count);
    blank = (_grey_info.drawmode & DRMODE_INVERSEVID) ?
             _grey_info.fg_brightness : _grey_info.bg_brightness;

    _grey_info.rb->memmove(_grey_info.buffer, _grey_info.buffer + shift,
                           length);
    _grey_info.rb->memset(_grey_info.buffer + length, blank, shift);
}

/* Scroll down */
void grey_scroll_down(int count)
{
    long shift, length;
    int blank;

    if ((unsigned)count >= (unsigned)_grey_info.height)
        return;

    shift = _GREY_MULUQ(_grey_info.width, count);
    length = _GREY_MULUQ(_grey_info.width, _grey_info.height - count);
    blank = (_grey_info.drawmode & DRMODE_INVERSEVID) ?
             _grey_info.fg_brightness : _grey_info.bg_brightness;

    _grey_info.rb->memmove(_grey_info.buffer + shift, _grey_info.buffer,
                           length);
    _grey_info.rb->memset(_grey_info.buffer, blank, shift);
}

/*** Unbuffered scrolling functions ***/

/* Scroll left */
void grey_ub_scroll_left(int count)
{
    unsigned char *data, *data_end;
    int blank, length;

    if ((unsigned)count >= (unsigned)_grey_info.width)
        return;

    data = _grey_info.values;
    data_end = data + _GREY_MULUQ(_grey_info.width, _grey_info.height);
    length = (_grey_info.width - count) << _GREY_BSHIFT;
    count <<= _GREY_BSHIFT;
    blank = _grey_info.gvalue[(_grey_info.drawmode & DRMODE_INVERSEVID) ?
                              _grey_info.fg_brightness :
                              _grey_info.bg_brightness];
    do
    {
        _grey_info.rb->memmove(data, data + count, length);
        data += length;
        _grey_info.rb->memset(data, blank, count);
        data += count;
    }
    while (data < data_end);
#ifdef SIMULATOR
    _grey_info.rb->sim_lcd_ex_update_rect(_grey_info.x, _grey_info.y,
                                          _grey_info.width, _grey_info.height);
#endif
}

/* Scroll right */
void grey_ub_scroll_right(int count)
{
    unsigned char *data, *data_end;
    int blank, length;

    if ((unsigned)count >= (unsigned)_grey_info.width)
        return;

    data = _grey_info.values;
    data_end = data + _GREY_MULUQ(_grey_info.width, _grey_info.height);
    length = (_grey_info.width - count) << _GREY_BSHIFT;
    count <<= _GREY_BSHIFT;
    blank = _grey_info.gvalue[(_grey_info.drawmode & DRMODE_INVERSEVID) ?
                              _grey_info.fg_brightness :
                              _grey_info.bg_brightness];
    do
    {
        _grey_info.rb->memmove(data + count, data, length);
        _grey_info.rb->memset(data, blank, count);
        data += _grey_info.width << _GREY_BSHIFT;
    }
    while (data < data_end);
#ifdef SIMULATOR
    _grey_info.rb->sim_lcd_ex_update_rect(_grey_info.x, _grey_info.y,
                                          _grey_info.width, _grey_info.height);
#endif
}

/* Scroll up */
void grey_ub_scroll_up(int count)
{
    unsigned char *dst, *end, *src;
    int blank;

    if ((unsigned)count >= (unsigned)_grey_info.height)
        return;

    dst   = _grey_info.values;
    end   = dst + _GREY_MULUQ(_grey_info.height, _grey_info.width);
    blank = _grey_info.gvalue[(_grey_info.drawmode & DRMODE_INVERSEVID) ?
                              _grey_info.fg_brightness :
                              _grey_info.bg_brightness];

#if (LCD_PIXELFORMAT == VERTICAL_PACKING) \
 || (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
    if (count & _GREY_BMASK)
    {
        /* Scrolling by fractional blocks - move pixel wise. */
        unsigned char *line_end;
        int ys, yd;

        for (ys = count, yd = 0; ys < _grey_info.height; ys++, yd++)
        {
            dst = _grey_info.values
                + _GREY_MULUQ(_grey_info.width, yd & ~_GREY_BMASK)
                + (~yd & _GREY_BMASK);
            src = _grey_info.values
                + _GREY_MULUQ(_grey_info.width, ys & ~_GREY_BMASK)
                + (~ys & _GREY_BMASK);
            line_end = dst + _grey_info.width * _GREY_BSIZE;

            do
            {
                *dst = *src;
                dst += _GREY_BSIZE;
                src += _GREY_BSIZE;
            }
            while (dst < line_end);
        }
        for (; yd & _GREY_BMASK; yd++)   /* Fill remainder of current block. */
        {
            dst = _grey_info.values
                + _GREY_MULUQ(_grey_info.width, yd & ~_GREY_BMASK)
                + (~yd & _GREY_BMASK);
            line_end = dst + _grey_info.width * _GREY_BSIZE;

            do
            {
                *dst = blank;
                dst += _GREY_BSIZE;
            }
            while (dst < line_end);
        }
    }
    else
#endif
    {
        int blen = _GREY_MULUQ(_grey_info.height - count, _grey_info.width);

        src = dst + _GREY_MULUQ(count, _grey_info.width);
        _grey_info.rb->memmove(dst, src, blen);
        dst += blen;
    }
    _grey_info.rb->memset(dst, blank, end - dst); /* Fill remainder at once. */
#ifdef SIMULATOR
    _grey_info.rb->sim_lcd_ex_update_rect(_grey_info.x, _grey_info.y,
                                          _grey_info.width, _grey_info.height);
#endif
}

/* Scroll down */
void grey_ub_scroll_down(int count)
{
    unsigned char *start, *dst;
    int blank;

    if ((unsigned)count >= (unsigned)_grey_info.height)
        return;

    start = _grey_info.values;
    dst   = start + _GREY_MULUQ(_grey_info.height, _grey_info.width);
    blank = _grey_info.gvalue[(_grey_info.drawmode & DRMODE_INVERSEVID) ?
                              _grey_info.fg_brightness :
                              _grey_info.bg_brightness];

#if (LCD_PIXELFORMAT == VERTICAL_PACKING) \
 || (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
    if (count & _GREY_BMASK)
    {
        /* Scrolling by fractional blocks - move pixel wise. */
        unsigned char *src, *line_end;
        int ys, yd;

        yd = _grey_info.height - 1;
        for (ys = yd - count; ys >= 0; ys--, yd--)
        {
            dst = _grey_info.values
                + _GREY_MULUQ(_grey_info.width, yd & ~_GREY_BMASK)
                + (~yd & _GREY_BMASK);
            src = _grey_info.values
                + _GREY_MULUQ(_grey_info.width, ys & ~_GREY_BMASK)
                + (~ys & _GREY_BMASK);
            line_end = dst + _grey_info.width * _GREY_BSIZE;

            do
            {
                *dst = *src;
                dst += _GREY_BSIZE;
                src += _GREY_BSIZE;
            }
            while (dst < line_end);
        }
        for (; ~yd & _GREY_BMASK; yd--)  /* Fill remainder of current block. */
        {
            dst = _grey_info.values
                + _GREY_MULUQ(_grey_info.width, yd & ~_GREY_BMASK)
                + (~yd & _GREY_BMASK);
            line_end = dst + _grey_info.width * _GREY_BSIZE;

            do
            {
                line_end -= _GREY_BSIZE;
                *line_end = blank;
            }
            while (dst < line_end);
        }
        /* Top pixel in a block has the highest address, but dst must point
         * to the lowest address in that block for the subsequent fill. */
        dst -= _GREY_BMASK;
    }
    else
#endif
    {
        int blen = _GREY_MULUQ(_grey_info.height - count, _grey_info.width);

        dst -= blen;
        _grey_info.rb->memmove(dst, start, blen);
    }
    _grey_info.rb->memset(start, blank, dst - start);
    /* Fill remainder at once. */
#ifdef SIMULATOR
    _grey_info.rb->sim_lcd_ex_update_rect(_grey_info.x, _grey_info.y,
                                          _grey_info.width, _grey_info.height);
#endif
}